|
76028
|
NULL
|
0
|
2026-04-24T07:22:54.456705+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777015374456_m1.jpg...
|
Firefox
|
(132) YouTube — Personal
|
True
|
www.youtube.com/watch?v=gK-oV8g3Y1A&list=RDgK- www.youtube.com/watch?v=gK-oV8g3Y1A&list=RDgK-oV8g3Y1A&start_radio=1...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(66) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) YouTube
(132) YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
domoracki
domoracki
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Domov
Domov
Domov
Shorts
Shorts
Shorts
Odbery
Odbery
Odbery
Unspeakable. K dispozícii je nový obsah.
Unspeakable
Unspeakable
EU Made Simple. K dispozícii je nový obsah.
EU Made Simple
EU Made Simple
Sam Harris. K dispozícii je nový obsah.
Sam Harris
Sam Harris
T90Official - Age Of Empires 2. K dispozícii je nový obsah.
T90Official - Age Of Empires 2
T90Official - Age Of Empires 2
TLDR News EU. K dispozícii je nový obsah.
TLDR News EU
TLDR News EU
Papa Ruzz. K dispozícii je nový obsah.
Papa Ruzz
Papa Ruzz
TE1 GAMING
TE1 GAMING
TE1 GAMING
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Moje
Moje
Moje
Váš kanál
Váš kanál
Váš kanál
História
História
História
Zoznamy
Zoznamy
Zoznamy
Pozrieť neskôr
Pozrieť neskôr
Pozrieť neskôr
Obľúbené videá
Obľúbené videá
Obľúbené videá
Vaše videá
Vaše videá
Vaše videá
Stiahnuté súbory
Stiahnuté súbory
Stiahnuté súbory
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Preskúmať
Preskúmať
Hudba
Hudba
Hudba
Hry
Hry
Hry
Šport
Šport
Šport
Viac zo služby YouTube
Viac zo služby YouTube
YouTube Premium
YouTube Premium
YouTube Premium
YouTube Music
YouTube Music
YouTube Music
YouTube Kids
YouTube Kids
YouTube Kids
História nahlasovania
História nahlasovania
História nahlasovania
Informácie
Informácie
Tlač
Tlač
Autorské práva
Autorské práva
Kontaktujte nás
Kontaktujte nás
Autori
Autori...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"5 Signs You Have Successfully Hurt a Narcissist; - kovaliklukas@gmail.com - Gmail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"(66) Inbox | kovaliklukas@proton.me | Proton Mail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Today's Deals","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today's Deals","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"architecture - screenpipe docs","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"architecture - screenpipe docs","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Platform","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Platform","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"rescue time detailed overview - Google Search","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"rescue time detailed overview - Google Search","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(132) YouTube","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"(132) YouTube","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sprievodca","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domovská stránka YouTube","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BG","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preskočiť navigáciu","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preskočiť navigáciu","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"domoracki","depth":15,"value":"domoracki","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"domoracki","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Vymazať vyhľadávací dopyt","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":13,"help_text":"Hľadať","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vyhľadávať hlasom","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vytvoriť","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vytvoriť","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upozornenia","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9+","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Ponuka účtu","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domov","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domov","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Domov","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Shorts","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Shorts","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Shorts","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Odbery","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Odbery","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odbery","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Unspeakable. K dispozícii je nový obsah.","depth":18,"help_text":"Unspeakable","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Unspeakable","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unspeakable","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"EU Made Simple. K dispozícii je nový obsah.","depth":18,"help_text":"EU Made Simple","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"EU Made Simple","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EU Made Simple","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sam Harris. K dispozícii je nový obsah.","depth":18,"help_text":"Sam Harris","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sam Harris","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sam Harris","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"T90Official - Age Of Empires 2. K dispozícii je nový obsah.","depth":18,"help_text":"T90Official - Age Of Empires 2","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"T90Official - Age Of Empires 2","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"T90Official - Age Of Empires 2","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TLDR News EU. K dispozícii je nový obsah.","depth":18,"help_text":"TLDR News EU","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TLDR News EU","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TLDR News EU","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Papa Ruzz. K dispozícii je nový obsah.","depth":18,"help_text":"Papa Ruzz","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Papa Ruzz","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Papa Ruzz","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TE1 GAMING","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TE1 GAMING","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TE1 GAMING","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zobraziť viac","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Moje","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Moje","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Moje","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Váš kanál","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Váš kanál","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Váš kanál","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"História","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"História","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"História","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Zoznamy","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zoznamy","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zoznamy","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pozrieť neskôr","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pozrieť neskôr","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pozrieť neskôr","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Obľúbené videá","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Obľúbené videá","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Obľúbené videá","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vaše videá","depth":20,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Vaše videá","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vaše videá","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Stiahnuté súbory","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Stiahnuté súbory","depth":22,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stiahnuté súbory","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":20,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":22,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zobraziť viac","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Preskúmať","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Preskúmať","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hudba","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Hudba","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hudba","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hry","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Hry","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hry","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Šport","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Šport","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Šport","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Viac zo služby YouTube","depth":16,"bounds":{"left":0.16388889,"top":0.0,"width":0.15,"height":0.035555556},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Viac zo služby YouTube","depth":18,"bounds":{"left":0.17222223,"top":0.0,"width":0.11736111,"height":0.02111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Premium","depth":18,"bounds":{"left":0.16388889,"top":0.0,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Premium","depth":19,"bounds":{"left":0.16388889,"top":0.0,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Premium","depth":21,"bounds":{"left":0.20555556,"top":0.0,"width":0.07951389,"height":0.018333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Music","depth":18,"bounds":{"left":0.16388889,"top":0.0044444446,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Music","depth":19,"bounds":{"left":0.16388889,"top":0.0044444446,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Music","depth":21,"bounds":{"left":0.20555556,"top":0.017777778,"width":0.06631944,"height":0.018333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Kids","depth":18,"bounds":{"left":0.16388889,"top":0.04888889,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Kids","depth":19,"bounds":{"left":0.16388889,"top":0.04888889,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Kids","depth":21,"bounds":{"left":0.20555556,"top":0.062222224,"width":0.059027776,"height":0.018333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"História nahlasovania","depth":18,"bounds":{"left":0.16388889,"top":0.12111111,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"História nahlasovania","depth":19,"bounds":{"left":0.16388889,"top":0.12111111,"width":0.14166667,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"História nahlasovania","depth":21,"bounds":{"left":0.20555556,"top":0.13444445,"width":0.09340278,"height":0.018333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Informácie","depth":16,"bounds":{"left":0.17222223,"top":0.19777778,"width":0.04375,"height":0.02},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Informácie","depth":17,"bounds":{"left":0.17222223,"top":0.19888888,"width":0.04375,"height":0.017777778},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Tlač","depth":16,"bounds":{"left":0.22152779,"top":0.19777778,"width":0.017361112,"height":0.02},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Tlač","depth":17,"bounds":{"left":0.22152779,"top":0.19888888,"width":0.017361112,"height":0.017777778},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Autorské práva","depth":16,"bounds":{"left":0.17222223,"top":0.21777777,"width":0.060763888,"height":0.02},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autorské práva","depth":17,"bounds":{"left":0.17222223,"top":0.2188889,"width":0.060763888,"height":0.017777778},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kontaktujte nás","depth":16,"bounds":{"left":0.17222223,"top":0.23777778,"width":0.063194446,"height":0.02},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontaktujte nás","depth":17,"bounds":{"left":0.17222223,"top":0.23888889,"width":0.063194446,"height":0.017777778},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Autori","depth":16,"bounds":{"left":0.24097222,"top":0.23777778,"width":0.024652777,"height":0.02},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autori","depth":17,"bounds":{"left":0.24097222,"top":0.23888889,"width":0.024652777,"height":0.017777778},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5023934186278916185
|
-3988266745553632567
|
click
|
accessibility
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(66) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) YouTube
(132) YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
domoracki
domoracki
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Domov
Domov
Domov
Shorts
Shorts
Shorts
Odbery
Odbery
Odbery
Unspeakable. K dispozícii je nový obsah.
Unspeakable
Unspeakable
EU Made Simple. K dispozícii je nový obsah.
EU Made Simple
EU Made Simple
Sam Harris. K dispozícii je nový obsah.
Sam Harris
Sam Harris
T90Official - Age Of Empires 2. K dispozícii je nový obsah.
T90Official - Age Of Empires 2
T90Official - Age Of Empires 2
TLDR News EU. K dispozícii je nový obsah.
TLDR News EU
TLDR News EU
Papa Ruzz. K dispozícii je nový obsah.
Papa Ruzz
Papa Ruzz
TE1 GAMING
TE1 GAMING
TE1 GAMING
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Moje
Moje
Moje
Váš kanál
Váš kanál
Váš kanál
História
História
História
Zoznamy
Zoznamy
Zoznamy
Pozrieť neskôr
Pozrieť neskôr
Pozrieť neskôr
Obľúbené videá
Obľúbené videá
Obľúbené videá
Vaše videá
Vaše videá
Vaše videá
Stiahnuté súbory
Stiahnuté súbory
Stiahnuté súbory
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Preskúmať
Preskúmať
Hudba
Hudba
Hudba
Hry
Hry
Hry
Šport
Šport
Šport
Viac zo služby YouTube
Viac zo služby YouTube
YouTube Premium
YouTube Premium
YouTube Premium
YouTube Music
YouTube Music
YouTube Music
YouTube Kids
YouTube Kids
YouTube Kids
História nahlasovania
História nahlasovania
História nahlasovania
Informácie
Informácie
Tlač
Tlač
Autorské práva
Autorské práva
Kontaktujte nás
Kontaktujte nás
Autori
Autori...
|
NULL
|
|
76029
|
NULL
|
0
|
2026-04-24T07:22:54.523443+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777015374523_m2.jpg...
|
Firefox
|
(132) YouTube — Personal
|
True
|
www.youtube.com/watch?v=gK-oV8g3Y1A&list=RDgK- www.youtube.com/watch?v=gK-oV8g3Y1A&list=RDgK-oV8g3Y1A&start_radio=1...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(66) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) YouTube
(132) YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
domoracki
domoracki
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Domov
Domov
Domov
Shorts
Shorts
Shorts
Odbery
Odbery
Odbery
Unspeakable. K dispozícii je nový obsah.
Unspeakable
Unspeakable
EU Made Simple. K dispozícii je nový obsah.
EU Made Simple
EU Made Simple
Sam Harris. K dispozícii je nový obsah.
Sam Harris
Sam Harris
T90Official - Age Of Empires 2. K dispozícii je nový obsah.
T90Official - Age Of Empires 2
T90Official - Age Of Empires 2
TLDR News EU. K dispozícii je nový obsah.
TLDR News EU
TLDR News EU
Papa Ruzz. K dispozícii je nový obsah.
Papa Ruzz
Papa Ruzz
TE1 GAMING
TE1 GAMING
TE1 GAMING
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Moje
Moje
Moje
Váš kanál
Váš kanál
Váš kanál
História
História
História
Zoznamy
Zoznamy
Zoznamy
Pozrieť neskôr
Pozrieť neskôr
Pozrieť neskôr
Obľúbené videá
Obľúbené videá
Obľúbené videá
Vaše videá
Vaše videá
Vaše videá
Stiahnuté súbory
Stiahnuté súbory
Stiahnuté súbory
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Preskúmať
Preskúmať
Hudba
Hudba
Hudba
Hry
Hry
Hry
Šport
Šport
Šport
Viac zo služby YouTube
Viac zo služby YouTube
YouTube Premium
YouTube Premium
YouTube Premium
YouTube Music
YouTube Music
YouTube Music
YouTube Kids
YouTube Kids
YouTube Kids
História nahlasovania
História nahlasovania
História nahlasovania
Informácie
Informácie
Tlač
Tlač
Autorské práva
Autorské práva
Kontaktujte nás
Kontaktujte nás
Autori
Autori
Inzercia
Inzercia
Vývojári
Vývojári
Zmluvné podmienky
Zmluvné podmienky
Ochrana súkromia
Ochrana súkromia
Pravidlá a bezpečnosť
Pravidlá a bezpečnosť
Ako funguje YouTube
Ako funguje YouTube
Testovať nové funkcie
Testovať nové funkcie
© 2026 Google LLC
Všetko
Všetko
Podcasty
Podcasty
Hudba
Hudba
Hry
Hry
Mixy
Mixy
Správy
Správy
Naživo
Naživo
Príroda
Príroda
Futbal
Futbal
Nedávno nahrané
Nedávno nahrané
Pozreté
Pozreté
Novinky pre vás
Novinky pre vás
MG Motor Bulgaria
Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране
Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране
Sponzorované
·
MG Motor Bulgaria
Moje centrum reklám
Pozerať
Pozerať
Získať kalkuláciu
Získať kalkuláciu
Prejsť na kanál The Duran...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.03673537,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"5 Signs You Have Successfully Hurt a Narcissist; - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.26961437,"top":0.0518755,"width":0.03656915,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"(66) Inbox | kovaliklukas@proton.me | Proton Mail","depth":4,"bounds":{"left":0.30618352,"top":0.0518755,"width":0.03673537,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.26263297,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Today's Deals","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today's Deals","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.024102394,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"architecture - screenpipe docs","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"architecture - screenpipe docs","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.053523935,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.20844415,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.2443484,"top":0.23703113,"width":0.037898935,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.040724736,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.03756649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Platform","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Platform","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.027925532,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"rescue time detailed overview - Google Search","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"rescue time detailed overview - Google Search","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.08128324,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":4,"bounds":{"left":0.23105054,"top":0.38946527,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":5,"bounds":{"left":0.2443484,"top":0.40063846,"width":0.09790558,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":4,"bounds":{"left":0.23105054,"top":0.42218676,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":5,"bounds":{"left":0.2443484,"top":0.43335995,"width":0.22556517,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":4,"bounds":{"left":0.23105054,"top":0.45490822,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":5,"bounds":{"left":0.2443484,"top":0.4660814,"width":0.08826463,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(132) YouTube","depth":4,"bounds":{"left":0.23105054,"top":0.48762968,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"(132) YouTube","depth":5,"bounds":{"left":0.2443484,"top":0.49880287,"width":0.024767287,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.3324468,"top":0.49481246,"width":0.007978723,"height":0.01915403},"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.23387633,"top":0.5219473,"width":0.108211435,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sprievodca","depth":13,"bounds":{"left":0.35272607,"top":0.06464485,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domovská stránka YouTube","depth":12,"bounds":{"left":0.36336437,"top":0.0518755,"width":0.04089096,"height":0.044692736},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BG","depth":13,"bounds":{"left":0.40093085,"top":0.061452515,"width":0.0043218085,"height":0.009577015},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preskočiť navigáciu","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preskočiť navigáciu","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"domoracki","depth":15,"bounds":{"left":0.57230717,"top":0.06464485,"width":0.15292554,"height":0.01915403},"value":"domoracki","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"domoracki","depth":16,"bounds":{"left":0.57230717,"top":0.066640064,"width":0.025099734,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Vymazať vyhľadávací dopyt","depth":14,"bounds":{"left":0.732879,"top":0.058260176,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":13,"bounds":{"left":0.74484706,"top":0.058260176,"width":0.021276595,"height":0.031923383},"help_text":"Hľadať","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vyhľadávať hlasom","depth":14,"bounds":{"left":0.77144283,"top":0.058260176,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vytvoriť","depth":14,"bounds":{"left":0.92137635,"top":0.059856344,"width":0.03474069,"height":0.028731046},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vytvoriť","depth":17,"bounds":{"left":0.9346742,"top":0.06783719,"width":0.016123671,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upozornenia","depth":15,"bounds":{"left":0.9587766,"top":0.058260176,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9+","depth":17,"bounds":{"left":0.9674202,"top":0.06384677,"width":0.004488032,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Ponuka účtu","depth":14,"bounds":{"left":0.97473407,"top":0.060654428,"width":0.019946808,"height":0.027134877},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domov","depth":18,"bounds":{"left":0.3487367,"top":0.10614525,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domov","depth":19,"bounds":{"left":0.3487367,"top":0.10614525,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Domov","depth":21,"bounds":{"left":0.36868352,"top":0.11572227,"width":0.01462766,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Shorts","depth":18,"bounds":{"left":0.3487367,"top":0.13806863,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Shorts","depth":19,"bounds":{"left":0.3487367,"top":0.13806863,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Shorts","depth":21,"bounds":{"left":0.36868352,"top":0.14764565,"width":0.013630319,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Odbery","depth":20,"bounds":{"left":0.3487367,"top":0.18994413,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Odbery","depth":21,"bounds":{"left":0.3487367,"top":0.18994413,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odbery","depth":23,"bounds":{"left":0.35272607,"top":0.19832402,"width":0.016954787,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Unspeakable. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.22186752,"width":0.06781915,"height":0.031923383},"help_text":"Unspeakable","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Unspeakable","depth":19,"bounds":{"left":0.3487367,"top":0.22186752,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unspeakable","depth":21,"bounds":{"left":0.36868352,"top":0.23144454,"width":0.026761968,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"EU Made Simple. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.25379092,"width":0.06781915,"height":0.031923383},"help_text":"EU Made Simple","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"EU Made Simple","depth":19,"bounds":{"left":0.3487367,"top":0.25379092,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EU Made Simple","depth":21,"bounds":{"left":0.36868352,"top":0.26336792,"width":0.033909574,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sam Harris. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.2857143,"width":0.06781915,"height":0.031923383},"help_text":"Sam Harris","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sam Harris","depth":19,"bounds":{"left":0.3487367,"top":0.2857143,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sam Harris","depth":21,"bounds":{"left":0.36868352,"top":0.2952913,"width":0.023105053,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"T90Official - Age Of Empires 2. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.31763768,"width":0.06781915,"height":0.031923383},"help_text":"T90Official - Age Of Empires 2","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"T90Official - Age Of Empires 2","depth":19,"bounds":{"left":0.3487367,"top":0.31763768,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"T90Official - Age Of Empires 2","depth":21,"bounds":{"left":0.36868352,"top":0.3272147,"width":0.061835106,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TLDR News EU. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.34956107,"width":0.06781915,"height":0.031923383},"help_text":"TLDR News EU","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TLDR News EU","depth":19,"bounds":{"left":0.3487367,"top":0.34956107,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TLDR News EU","depth":21,"bounds":{"left":0.36868352,"top":0.35913807,"width":0.030917553,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Papa Ruzz. K dispozícii je nový obsah.","depth":18,"bounds":{"left":0.3487367,"top":0.38148445,"width":0.06781915,"height":0.031923383},"help_text":"Papa Ruzz","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Papa Ruzz","depth":19,"bounds":{"left":0.3487367,"top":0.38148445,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Papa Ruzz","depth":21,"bounds":{"left":0.36868352,"top":0.39106146,"width":0.021775266,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"TE1 GAMING","depth":18,"bounds":{"left":0.3487367,"top":0.41340783,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TE1 GAMING","depth":19,"bounds":{"left":0.3487367,"top":0.41340783,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TE1 GAMING","depth":21,"bounds":{"left":0.36868352,"top":0.42298484,"width":0.027260639,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":18,"bounds":{"left":0.3487367,"top":0.44533122,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":19,"bounds":{"left":0.3487367,"top":0.44533122,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":20,"bounds":{"left":0.3487367,"top":0.44533122,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zobraziť viac","depth":22,"bounds":{"left":0.36868352,"top":0.45490822,"width":0.026595745,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Moje","depth":20,"bounds":{"left":0.3487367,"top":0.49720672,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Moje","depth":21,"bounds":{"left":0.3487367,"top":0.49720672,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Moje","depth":23,"bounds":{"left":0.35272607,"top":0.50558656,"width":0.011801862,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Váš kanál","depth":20,"bounds":{"left":0.3487367,"top":0.5291301,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Váš kanál","depth":21,"bounds":{"left":0.3487367,"top":0.5291301,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Váš kanál","depth":23,"bounds":{"left":0.36868352,"top":0.5387071,"width":0.020113032,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"História","depth":20,"bounds":{"left":0.3487367,"top":0.56105345,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"História","depth":21,"bounds":{"left":0.3487367,"top":0.56105345,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"História","depth":23,"bounds":{"left":0.36868352,"top":0.5706305,"width":0.016289894,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Zoznamy","depth":20,"bounds":{"left":0.3487367,"top":0.59297687,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zoznamy","depth":21,"bounds":{"left":0.3487367,"top":0.59297687,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zoznamy","depth":23,"bounds":{"left":0.36868352,"top":0.60255384,"width":0.019115692,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pozrieť neskôr","depth":20,"bounds":{"left":0.3487367,"top":0.6249002,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pozrieť neskôr","depth":21,"bounds":{"left":0.3487367,"top":0.6249002,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pozrieť neskôr","depth":23,"bounds":{"left":0.36868352,"top":0.63447726,"width":0.029753989,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Obľúbené videá","depth":20,"bounds":{"left":0.3487367,"top":0.65682364,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Obľúbené videá","depth":21,"bounds":{"left":0.3487367,"top":0.65682364,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Obľúbené videá","depth":23,"bounds":{"left":0.36868352,"top":0.6664006,"width":0.032081116,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vaše videá","depth":20,"bounds":{"left":0.3487367,"top":0.688747,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Vaše videá","depth":21,"bounds":{"left":0.3487367,"top":0.688747,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vaše videá","depth":23,"bounds":{"left":0.36868352,"top":0.698324,"width":0.02244016,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Stiahnuté súbory","depth":21,"bounds":{"left":0.3487367,"top":0.7206704,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Stiahnuté súbory","depth":22,"bounds":{"left":0.3487367,"top":0.7206704,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stiahnuté súbory","depth":24,"bounds":{"left":0.36868352,"top":0.7302474,"width":0.034906916,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":20,"bounds":{"left":0.3487367,"top":0.75259376,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":21,"bounds":{"left":0.3487367,"top":0.75259376,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Zobraziť viac","depth":22,"bounds":{"left":0.3487367,"top":0.75259376,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zobraziť viac","depth":24,"bounds":{"left":0.36868352,"top":0.7621708,"width":0.026595745,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Preskúmať","depth":16,"bounds":{"left":0.3487367,"top":0.8044693,"width":0.07180851,"height":0.025538707},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Preskúmať","depth":18,"bounds":{"left":0.35272607,"top":0.8104549,"width":0.025930852,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hudba","depth":18,"bounds":{"left":0.3487367,"top":0.830008,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Hudba","depth":19,"bounds":{"left":0.3487367,"top":0.830008,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hudba","depth":21,"bounds":{"left":0.36868352,"top":0.839585,"width":0.013630319,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hry","depth":18,"bounds":{"left":0.3487367,"top":0.8619314,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Hry","depth":19,"bounds":{"left":0.3487367,"top":0.8619314,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hry","depth":21,"bounds":{"left":0.36868352,"top":0.87150836,"width":0.0071476065,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Šport","depth":18,"bounds":{"left":0.3487367,"top":0.89385474,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Šport","depth":19,"bounds":{"left":0.3487367,"top":0.89385474,"width":0.06781915,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Šport","depth":21,"bounds":{"left":0.36868352,"top":0.9034318,"width":0.011303191,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Viac zo služby YouTube","depth":16,"bounds":{"left":0.3487367,"top":0.94573027,"width":0.07180851,"height":0.025538707},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Viac zo služby YouTube","depth":18,"bounds":{"left":0.35272607,"top":0.9517159,"width":0.05618351,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Premium","depth":18,"bounds":{"left":0.3487367,"top":0.97126895,"width":0.06781915,"height":0.028731048},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Premium","depth":19,"bounds":{"left":0.3487367,"top":0.97126895,"width":0.06781915,"height":0.028731048},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Premium","depth":21,"bounds":{"left":0.36868352,"top":0.980846,"width":0.038065158,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Music","depth":18,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.0031923056},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Music","depth":19,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.0031923056},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Music","depth":21,"bounds":{"left":0.36868352,"top":1.0,"width":0.03174867,"height":-0.0127693415},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"YouTube Kids","depth":18,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.03511572},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"YouTube Kids","depth":19,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.03511572},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"YouTube Kids","depth":21,"bounds":{"left":0.36868352,"top":1.0,"width":0.02825798,"height":-0.044692755},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"História nahlasovania","depth":18,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.08699119},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"História nahlasovania","depth":19,"bounds":{"left":0.3487367,"top":1.0,"width":0.06781915,"height":-0.08699119},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"História nahlasovania","depth":21,"bounds":{"left":0.36868352,"top":1.0,"width":0.044714097,"height":-0.09656823},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Informácie","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Informácie","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Tlač","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Tlač","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Autorské práva","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autorské práva","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kontaktujte nás","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontaktujte nás","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Autori","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autori","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inzercia","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inzercia","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vývojári","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vývojári","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Zmluvné podmienky","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zmluvné podmienky","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Ochrana súkromia","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ochrana súkromia","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pravidlá a bezpečnosť","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pravidlá a bezpečnosť","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Ako funguje YouTube","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ako funguje YouTube","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Testovať nové funkcie","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Testovať nové funkcie","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"© 2026 Google LLC","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Všetko","depth":17,"bounds":{"left":0.4325133,"top":0.10614525,"width":0.02244016,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Všetko","depth":19,"bounds":{"left":0.43650267,"top":0.112529926,"width":0.014461436,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Podcasty","depth":17,"bounds":{"left":0.45894283,"top":0.10614525,"width":0.027426861,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Podcasty","depth":19,"bounds":{"left":0.46293217,"top":0.112529926,"width":0.019448139,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hudba","depth":17,"bounds":{"left":0.49035904,"top":0.10614525,"width":0.021609042,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hudba","depth":19,"bounds":{"left":0.4943484,"top":0.112529926,"width":0.013630319,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hry","depth":17,"bounds":{"left":0.5159575,"top":0.10614525,"width":0.015292553,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hry","depth":19,"bounds":{"left":0.5199468,"top":0.112529926,"width":0.00731383,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Mixy","depth":17,"bounds":{"left":0.53523934,"top":0.10614525,"width":0.017785905,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Mixy","depth":19,"bounds":{"left":0.53922874,"top":0.112529926,"width":0.009807181,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Správy","depth":17,"bounds":{"left":0.55701464,"top":0.10614525,"width":0.022107713,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Správy","depth":19,"bounds":{"left":0.561004,"top":0.112529926,"width":0.01412899,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Naživo","depth":17,"bounds":{"left":0.5831117,"top":0.10614525,"width":0.022107713,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Naživo","depth":19,"bounds":{"left":0.58710104,"top":0.112529926,"width":0.01412899,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Príroda","depth":17,"bounds":{"left":0.60920876,"top":0.10614525,"width":0.023271276,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Príroda","depth":19,"bounds":{"left":0.61319816,"top":0.112529926,"width":0.015292553,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Futbal","depth":17,"bounds":{"left":0.6364694,"top":0.10614525,"width":0.020944148,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Futbal","depth":19,"bounds":{"left":0.64045876,"top":0.112529926,"width":0.012965426,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nedávno nahrané","depth":17,"bounds":{"left":0.66140294,"top":0.10614525,"width":0.04438165,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nedávno nahrané","depth":19,"bounds":{"left":0.6653923,"top":0.112529926,"width":0.036402926,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pozreté","depth":17,"bounds":{"left":0.70977396,"top":0.10614525,"width":0.023936171,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pozreté","depth":19,"bounds":{"left":0.7137633,"top":0.112529926,"width":0.015957447,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Novinky pre vás","depth":17,"bounds":{"left":0.73769945,"top":0.10614525,"width":0.04089096,"height":0.025538707},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Novinky pre vás","depth":19,"bounds":{"left":0.74168885,"top":0.112529926,"width":0.032912236,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"MG Motor Bulgaria","depth":19,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране","depth":21,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sponzorované","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"·","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"MG Motor Bulgaria","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Moje centrum reklám","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pozerať","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pozerať","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Získať kalkuláciu","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Získať kalkuláciu","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Prejsť na kanál The Duran","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
4491361290492592631
|
-3988354161023384887
|
click
|
accessibility
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(66) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) YouTube
(132) YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
domoracki
domoracki
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Domov
Domov
Domov
Shorts
Shorts
Shorts
Odbery
Odbery
Odbery
Unspeakable. K dispozícii je nový obsah.
Unspeakable
Unspeakable
EU Made Simple. K dispozícii je nový obsah.
EU Made Simple
EU Made Simple
Sam Harris. K dispozícii je nový obsah.
Sam Harris
Sam Harris
T90Official - Age Of Empires 2. K dispozícii je nový obsah.
T90Official - Age Of Empires 2
T90Official - Age Of Empires 2
TLDR News EU. K dispozícii je nový obsah.
TLDR News EU
TLDR News EU
Papa Ruzz. K dispozícii je nový obsah.
Papa Ruzz
Papa Ruzz
TE1 GAMING
TE1 GAMING
TE1 GAMING
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Moje
Moje
Moje
Váš kanál
Váš kanál
Váš kanál
História
História
História
Zoznamy
Zoznamy
Zoznamy
Pozrieť neskôr
Pozrieť neskôr
Pozrieť neskôr
Obľúbené videá
Obľúbené videá
Obľúbené videá
Vaše videá
Vaše videá
Vaše videá
Stiahnuté súbory
Stiahnuté súbory
Stiahnuté súbory
Zobraziť viac
Zobraziť viac
Zobraziť viac
Zobraziť viac
Preskúmať
Preskúmať
Hudba
Hudba
Hudba
Hry
Hry
Hry
Šport
Šport
Šport
Viac zo služby YouTube
Viac zo služby YouTube
YouTube Premium
YouTube Premium
YouTube Premium
YouTube Music
YouTube Music
YouTube Music
YouTube Kids
YouTube Kids
YouTube Kids
História nahlasovania
História nahlasovania
História nahlasovania
Informácie
Informácie
Tlač
Tlač
Autorské práva
Autorské práva
Kontaktujte nás
Kontaktujte nás
Autori
Autori
Inzercia
Inzercia
Vývojári
Vývojári
Zmluvné podmienky
Zmluvné podmienky
Ochrana súkromia
Ochrana súkromia
Pravidlá a bezpečnosť
Pravidlá a bezpečnosť
Ako funguje YouTube
Ako funguje YouTube
Testovať nové funkcie
Testovať nové funkcie
© 2026 Google LLC
Všetko
Všetko
Podcasty
Podcasty
Hudba
Hudba
Hry
Hry
Mixy
Mixy
Správy
Správy
Naživo
Naživo
Príroda
Príroda
Futbal
Futbal
Nedávno nahrané
Nedávno nahrané
Pozreté
Pozreté
Novinky pre vás
Novinky pre vás
MG Motor Bulgaria
Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране
Вземете MG ZS само за 117 € / 228 лв на месец. Заявете пробно шофиране
Sponzorované
·
MG Motor Bulgaria
Moje centrum reklám
Pozerať
Pozerať
Získať kalkuláciu
Získať kalkuláciu
Prejsť na kanál The Duran...
|
76027
|
|
76088
|
NULL
|
0
|
2026-04-24T07:28:02.735124+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777015682735_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
NULL
|
-8496811010192975640
|
NULL
|
click
|
ocr
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
76042
|
|
76089
|
NULL
|
0
|
2026-04-24T07:28:02.791490+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777015682791_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
3168285612613231679
|
NULL
|
click
|
ocr
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
76044
|
|
76155
|
NULL
|
0
|
2026-04-24T07:33:23.910839+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016003910_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"15","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8210130048459164633
|
-814333409455543525
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76156
|
NULL
|
0
|
2026-04-24T07:33:25.186019+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016005186_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
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.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","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.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59574467,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.60538566,"top":0.3216281,"width":0.00731383,"height":0.018355945},"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.61269945,"top":0.3216281,"width":0.006981383,"height":0.018355945},"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.3200319,"width":0.34375,"height":0.6799681},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"15","depth":4,"bounds":{"left":0.96276593,"top":0.10055866,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8210130048459164633
|
-814333409455543525
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12011 on JY-20157-AJ-rep Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
15
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76153
|
|
76258
|
NULL
|
0
|
2026-04-24T07:38:30.766035+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016310766_m1.jpg...
|
Firefox
|
Login - SonarQube Cloud — Work
|
True
|
sonarcloud.io/login?return_to=%2Fcomponent_measure sonarcloud.io/login?return_to=%2Fcomponent_measures%3Fid%3Djiminny_app%26pullRequest%3D12011%26metric%3Dnew_coverage%26view%3Dlist...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Login - SonarQube Cloud
Login - SonarQube Cloud
Close tab
Pipelines - jiminny/app
Pipelines - jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Log in or Sign up with:
Log in or Sign up with:
GitHub GitHub
GitHub
Bitbucket Bitbucket
Bitbucket
Gitlab GitLab
GitLab
Azure DevOps Azure DevOps
Azure DevOps
Only available on Enterprise plan
Log in with SSO
Log in with SSO
By logging in, you're agreeing to our
Terms of Service
Terms of Service
.
By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.
Accept All Cookies
Reject All
No, let me choose
Waiting for sonarcloud.io…...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login - SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Login - SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Log in or Sign up with:","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log in or Sign up with:","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"GitHub GitHub","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"GitHub","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Bitbucket Bitbucket","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Bitbucket","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gitlab GitLab","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitLab","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Azure DevOps Azure DevOps","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Azure DevOps","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Only available on Enterprise plan","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Log in with SSO","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Log in with SSO","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"By logging in, you're agreeing to our","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms of Service","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms of Service","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.","depth":11,"bounds":{"left":0.09548611,"top":0.0,"width":0.7607639,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Accept All Cookies","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Reject All","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"No, let me choose","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Waiting for sonarcloud.io…","depth":5,"bounds":{"left":0.08715278,"top":0.0,"width":0.096875,"height":0.015},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7424995971034840790
|
-7683330421027052854
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Login - SonarQube Cloud
Login - SonarQube Cloud
Close tab
Pipelines - jiminny/app
Pipelines - jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Log in or Sign up with:
Log in or Sign up with:
GitHub GitHub
GitHub
Bitbucket Bitbucket
Bitbucket
Gitlab GitLab
GitLab
Azure DevOps Azure DevOps
Azure DevOps
Only available on Enterprise plan
Log in with SSO
Log in with SSO
By logging in, you're agreeing to our
Terms of Service
Terms of Service
.
By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.
Accept All Cookies
Reject All
No, let me choose
Waiting for sonarcloud.io…...
|
NULL
|
|
76259
|
NULL
|
0
|
2026-04-24T07:38:30.680219+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016310680_m2.jpg...
|
Firefox
|
Login - SonarQube Cloud — Work
|
True
|
sonarcloud.io/login?return_to=%2Fcomponent_measure sonarcloud.io/login?return_to=%2Fcomponent_measures%3Fid%3Djiminny_app%26pullRequest%3D12011%26metric%3Dnew_coverage%26view%3Dlist...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Login - SonarQube Cloud
Login - SonarQube Cloud
Close tab
Pipelines - jiminny/app
Pipelines - jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Log in or Sign up with:
Log in or Sign up with:
GitHub GitHub
GitHub
Bitbucket Bitbucket
Bitbucket
Gitlab GitLab
GitLab
Azure DevOps Azure DevOps
Azure DevOps
Only available on Enterprise plan
Log in with SSO
Log in with SSO
By logging in, you're agreeing to our
Terms of Service
Terms of Service
.
By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.
Accept All Cookies
Reject All
No, let me choose
Waiting for sonarcloud.io…...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.16555852,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.23703113,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Login - SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Login - SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.044049203,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29837102,"top":0.29848364,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.15924202,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Log in or Sign up with:","depth":9,"bounds":{"left":0.6087101,"top":0.22426178,"width":0.0930851,"height":0.0830008},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Log in or Sign up with:","depth":10,"bounds":{"left":0.61668885,"top":0.24381484,"width":0.076961435,"height":0.06344773},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"GitHub GitHub","depth":13,"bounds":{"left":0.6087101,"top":0.3264166,"width":0.0930851,"height":0.0415004},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"GitHub","depth":14,"bounds":{"left":0.62666225,"top":0.33798882,"width":0.023271276,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Bitbucket Bitbucket","depth":13,"bounds":{"left":0.6087101,"top":0.38068634,"width":0.0930851,"height":0.0415004},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Bitbucket","depth":14,"bounds":{"left":0.62666225,"top":0.39225858,"width":0.032912236,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gitlab GitLab","depth":13,"bounds":{"left":0.6087101,"top":0.4349561,"width":0.0930851,"height":0.0415004},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitLab","depth":14,"bounds":{"left":0.62666225,"top":0.44652835,"width":0.021941489,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Azure DevOps Azure DevOps","depth":13,"bounds":{"left":0.6087101,"top":0.48922586,"width":0.0930851,"height":0.0415004},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Azure DevOps","depth":14,"bounds":{"left":0.62666225,"top":0.5007981,"width":0.047041222,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Only available on Enterprise plan","depth":11,"bounds":{"left":0.6140292,"top":0.5837989,"width":0.08228058,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Log in with SSO","depth":10,"bounds":{"left":0.6087101,"top":0.61372703,"width":0.0930851,"height":0.0415004},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Log in with SSO","depth":11,"bounds":{"left":0.62898934,"top":0.6252993,"width":0.05236037,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"By logging in, you're agreeing to our","depth":10,"bounds":{"left":0.60954124,"top":0.6763767,"width":0.09125665,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms of Service","depth":10,"bounds":{"left":0.63297874,"top":0.6955307,"width":0.04288564,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms of Service","depth":11,"bounds":{"left":0.63297874,"top":0.6955307,"width":0.04288564,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.67586434,"top":0.6955307,"width":0.0014960107,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.","depth":11,"bounds":{"left":0.3159907,"top":0.9660814,"width":0.36419547,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Accept All Cookies","depth":12,"bounds":{"left":0.8557181,"top":0.95730245,"width":0.047539894,"height":0.0311253},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Reject All","depth":12,"bounds":{"left":0.9065825,"top":0.95730245,"width":0.04155585,"height":0.0311253},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"No, let me choose","depth":12,"bounds":{"left":0.95146275,"top":0.95810056,"width":0.04155585,"height":0.02952913},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Waiting for sonarcloud.io…","depth":5,"bounds":{"left":0.31200132,"top":0.9876297,"width":0.04637633,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7424995971034840790
|
-7683330421027052854
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Login - SonarQube Cloud
Login - SonarQube Cloud
Close tab
Pipelines - jiminny/app
Pipelines - jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Log in or Sign up with:
Log in or Sign up with:
GitHub GitHub
GitHub
Bitbucket Bitbucket
Bitbucket
Gitlab GitLab
GitLab
Azure DevOps Azure DevOps
Azure DevOps
Only available on Enterprise plan
Log in with SSO
Log in with SSO
By logging in, you're agreeing to our
Terms of Service
Terms of Service
.
By clicking “Accept All Cookies”, you agree to the storing of cookies on your device to enhance site navigation, analyze site usage, and assist in our marketing efforts.
Accept All Cookies
Reject All
No, let me choose
Waiting for sonarcloud.io…...
|
NULL
|
|
76352
|
NULL
|
0
|
2026-04-24T07:43:43.475854+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016623475_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"role_description":"text"},{"role":"AXTextField","text":"JY-20157 add test coverage","depth":3,"value":"JY-20157 add test coverage","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-9028934553602785414
|
8404466858115443482
|
app_switch
|
accessibility
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}...
|
NULL
|
|
76353
|
NULL
|
0
|
2026-04-24T07:43:43.627756+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016623627_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"2 files committed","depth":2,"bounds":{"left":0.8753325,"top":0.91300875,"width":0.100398935,"height":0.013567438},"role_description":"text"},{"role":"AXTextField","text":"JY-20157 add test coverage","depth":3,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.11037234,"height":0.013567438},"value":"JY-20157 add test coverage","help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"bounds":{"left":0.8753325,"top":0.92897046,"width":0.05817819,"height":0.013567438},"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"text/html","depth":4,"help_text":"text/html","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Edit Commit Message…","depth":2,"bounds":{"left":0.8753325,"top":0.9481245,"width":0.048204787,"height":0.013567438},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#12011 on JY-20157-AJ-report-not-send-notification, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #12011 exists for current branch JY-20157-AJ-report-not-send-notification","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.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.59541225,"top":0.32322428,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6050532,"top":0.3216281,"width":0.00731383,"height":0.018355945},"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.61236703,"top":0.3216281,"width":0.006981383,"height":0.018355945},"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.070231445,"width":0.34375,"height":0.92976856},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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.30851063,"top":0.05027933,"width":0.008643617,"height":0.01915403},"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.31948137,"top":0.05027933,"width":0.008643617,"height":0.01915403},"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.328125,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.33676863,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.34541222,"top":0.05027933,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
105150503854657824
|
8404466858115443482
|
app_switch
|
accessibility
|
NULL
|
2 files committed
JY-20157 add test coverage
text/ 2 files committed
JY-20157 add test coverage
text/html
text/html
text/html
Edit Commit Message…
Project: faVsco.js, menu
#12011 on JY-20157-AJ-report-not-send-notification, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76382
|
NULL
|
0
|
2026-04-24T07:48:43.597740+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016923597_m1.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 12s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
6m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
2m 1s
2m 1s
RUNNING job test-backend-lint
test-backend-lint
876691
4m 15s
4m 15s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
7m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
8m 44s
8m 44s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
8m 43s
8m 43s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
24m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Home","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"bounds":{"left":0.10034722,"top":0.0,"width":0.029166667,"height":0.064444445},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"bounds":{"left":0.10034722,"top":0.0,"width":0.029166667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All pipelines","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All branches","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cutoff date","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Display options","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57701","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57701","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14m 12s","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876688","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876692","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876693","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 41s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 41s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876689","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"50s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"50s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876690","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876694","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 28s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 28s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876695","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 1s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 1s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876691","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 15s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 15s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876696","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876687","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 1s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 1s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57700","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57700","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876678","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 18s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 18s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876681","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 44s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 44s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876682","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-backend","depth":14,"bounds":{"left":0.32534721,"top":0.0,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.35729167,"top":0.0,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876679","depth":16,"bounds":{"left":0.43020833,"top":0.0,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 43s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 43s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job phpstan","depth":14,"bounds":{"left":0.32534721,"top":0.0,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.35729167,"top":0.0,"width":0.03784722,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876685","depth":16,"bounds":{"left":0.40069443,"top":0.0,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"bounds":{"left":0.32534721,"top":0.0,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.0,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876683","depth":16,"bounds":{"left":0.38923612,"top":0.0,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test","depth":14,"bounds":{"left":0.32534721,"top":0.011666667,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.35729167,"top":0.015555556,"width":0.018055556,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876684","depth":16,"bounds":{"left":0.38090277,"top":0.015555556,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-backend-lint","depth":14,"bounds":{"left":0.32534721,"top":0.047222223,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"bounds":{"left":0.35729167,"top":0.05111111,"width":0.08125,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876680","depth":16,"bounds":{"left":0.44409722,"top":0.05111111,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job sonar_cloud","depth":14,"bounds":{"left":0.32534721,"top":0.082777776,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"bounds":{"left":0.35729167,"top":0.086666666,"width":0.05625,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876686","depth":16,"bounds":{"left":0.41909721,"top":0.086666666,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.3045139,"top":0.14277777,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.32951388,"top":0.145,"width":0.06979167,"height":0.032222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.3517361,"top":0.15166667,"width":0.03923611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.44409722,"top":0.15,"width":0.07326389,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.44409722,"top":0.15111111,"width":0.07326389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52847224,"top":0.1538889,"width":0.023263888,"height":0.013888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.63125,"top":0.14055556,"width":0.19791667,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.63125,"top":0.14166667,"width":0.19791667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.16666667,"width":0.26666668,"height":0.046666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"bounds":{"left":0.63125,"top":0.16888888,"width":0.041319445,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"bounds":{"left":0.63125,"top":0.16888888,"width":0.25659722,"height":0.042777777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.15111111,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.15111111,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.24833333,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.32534721,"top":0.24444444,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.24833333,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876677","depth":16,"bounds":{"left":0.38923612,"top":0.24833333,"width":0.034722224,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.17465279,"top":0.3172222,"width":0.017361112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57699","depth":12,"bounds":{"left":0.17465279,"top":0.34055555,"width":0.029513888,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57699","depth":13,"bounds":{"left":0.17465279,"top":0.34166667,"width":0.029513888,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.3045139,"top":0.32,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.32951388,"top":0.32222223,"width":0.06979167,"height":0.032222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.3517361,"top":0.3288889,"width":0.03923611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.44409722,"top":0.32722223,"width":0.09548611,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.44409722,"top":0.32833335,"width":0.09548611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"bounds":{"left":0.63125,"top":0.31777778,"width":0.124305554,"height":0.022222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"bounds":{"left":0.63125,"top":0.31944445,"width":0.124305554,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.34444445,"width":0.26666668,"height":0.046666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"bounds":{"left":0.63125,"top":0.34611112,"width":0.041666668,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"bounds":{"left":0.63125,"top":0.34611112,"width":0.18333334,"height":0.042777777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.32833335,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.32833335,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.42555556,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.32534721,"top":0.42222223,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.35729167,"top":0.42555556,"width":0.07048611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876659","depth":16,"bounds":{"left":0.43333334,"top":0.42555556,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 19s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 19s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.45777777,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.4611111,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876660","depth":16,"bounds":{"left":0.43020833,"top":0.4611111,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 55s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 55s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.49333334,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.49666667,"width":0.0625,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876661","depth":16,"bounds":{"left":0.4253472,"top":0.49666667,"width":0.034027778,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 57s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 57s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"bounds":{"left":0.32534721,"top":0.5288889,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.35729167,"top":0.5322222,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876662","depth":16,"bounds":{"left":0.43020833,"top":0.5322222,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 10s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 10s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"bounds":{"left":0.32534721,"top":0.5644444,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.35729167,"top":0.56777775,"width":0.03784722,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876663","depth":16,"bounds":{"left":0.40069443,"top":0.56777775,"width":0.036111113,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.6,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.60333335,"width":0.15069444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876668","depth":16,"bounds":{"left":0.51354164,"top":0.60333335,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.63555557,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.6388889,"width":0.17048611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876669","depth":16,"bounds":{"left":0.53333336,"top":0.6388889,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.6711111,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.67444444,"width":0.16215278,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876671","depth":16,"bounds":{"left":0.525,"top":0.67444444,"width":0.033680554,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.70666665,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.71,"width":0.19166666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876670","depth":16,"bounds":{"left":0.5545139,"top":0.71,"width":0.034722224,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 52s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 52s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.74222225,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.7455556,"width":0.10451389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876672","depth":16,"bounds":{"left":0.46736112,"top":0.7455556,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"15s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_backend_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.7777778,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_backend_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.7811111,"width":0.17777778,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876674","depth":16,"bounds":{"left":0.540625,"top":0.7811111,"width":0.034722224,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5m 13s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5m 13s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.81333333,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.81666666,"width":0.16979167,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876676","depth":16,"bounds":{"left":0.5326389,"top":0.81666666,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_video_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.8488889,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_video_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.8522222,"width":0.19895834,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876673","depth":16,"bounds":{"left":0.56180555,"top":0.8522222,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"46s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"46s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_frontend_assets_to_s3_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.8844444,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_frontend_assets_to_s3_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.8877778,"width":0.17847222,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876675","depth":16,"bounds":{"left":0.54131943,"top":0.8877778,"width":0.034722224,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.32534721,"top":0.92,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.92333335,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876664","depth":16,"bounds":{"left":0.38923612,"top":0.92333335,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test","depth":14,"bounds":{"left":0.32534721,"top":0.95555556,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.35729167,"top":0.9588889,"width":0.018055556,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876665","depth":16,"bounds":{"left":0.38090277,"top":0.9588889,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"bounds":{"left":0.32534721,"top":0.9911111,"width":0.6746528,"height":0.0088889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-1566836784055955748
|
-8356881535935286600
|
idle
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 12s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
6m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
2m 1s
2m 1s
RUNNING job test-backend-lint
test-backend-lint
876691
4m 15s
4m 15s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
7m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
8m 44s
8m 44s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
8m 43s
8m 43s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
24m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint...
|
NULL
|
|
76383
|
NULL
|
0
|
2026-04-24T07:48:43.701048+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777016923701_m2.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 11s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
6m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
2m 2s
2m 2s
RUNNING job test-backend-lint
test-backend-lint
876691
4m 16s
4m 16s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
7m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
8m 44s
8m 44s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
8m 43s
8m 43s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
24m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
25m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
25m ago
Copy timestamp duration to clipboard...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.16555852,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.23703113,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.07679521,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29837102,"top":0.3312051,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.15924202,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"bounds":{"left":0.31831783,"top":0.061452515,"width":0.044215426,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"bounds":{"left":0.9371675,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"bounds":{"left":0.9517952,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"bounds":{"left":0.96642286,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"bounds":{"left":0.98105055,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"bounds":{"left":0.3179854,"top":0.10295291,"width":0.01462766,"height":0.035115723},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Home","depth":10,"bounds":{"left":0.3159907,"top":0.15083799,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"bounds":{"left":0.31881648,"top":0.1839585,"width":0.012965426,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"bounds":{"left":0.3159907,"top":0.21308859,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"bounds":{"left":0.31499335,"top":0.2462091,"width":0.020611702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"bounds":{"left":0.3159907,"top":0.2753392,"width":0.01861702,"height":0.04668795},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"bounds":{"left":0.31632313,"top":0.3084597,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"bounds":{"left":0.3159907,"top":0.33798882,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"bounds":{"left":0.31648937,"top":0.37071028,"width":0.01761968,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"bounds":{"left":0.3159907,"top":0.40023944,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"bounds":{"left":0.31665558,"top":0.4329609,"width":0.017287234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"bounds":{"left":0.3159907,"top":0.46249002,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"bounds":{"left":0.31632313,"top":0.49561054,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"bounds":{"left":0.3159907,"top":0.52474064,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"bounds":{"left":0.32130983,"top":0.55786115,"width":0.007978723,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"bounds":{"left":0.3159907,"top":0.58699125,"width":0.01861702,"height":0.04668795},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"bounds":{"left":0.32064494,"top":0.6201117,"width":0.00930851,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"bounds":{"left":0.31831783,"top":0.9345571,"width":0.013962766,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"bounds":{"left":0.31831783,"top":0.96727854,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"bounds":{"left":0.34823802,"top":0.1245012,"width":0.042054523,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"bounds":{"left":0.35887632,"top":0.12609737,"width":0.030086435,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"bounds":{"left":0.3957779,"top":0.1245012,"width":0.021775266,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"bounds":{"left":0.40641624,"top":0.12609737,"width":0.009807181,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"bounds":{"left":0.35887632,"top":0.16400638,"width":0.016954787,"height":0.029130088},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.35887632,"top":0.16480447,"width":0.016954787,"height":0.027533919},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"bounds":{"left":0.34823802,"top":0.19952115,"width":0.024102394,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"bounds":{"left":0.34823802,"top":0.20151636,"width":0.024102394,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"bounds":{"left":0.3776596,"top":0.19952115,"width":0.021110373,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.3776596,"top":0.20151636,"width":0.021110373,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"bounds":{"left":0.4040891,"top":0.19952115,"width":0.020611702,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"bounds":{"left":0.4040891,"top":0.20151636,"width":0.020611702,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"bounds":{"left":0.86984706,"top":0.16400638,"width":0.057845745,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"bounds":{"left":0.88580453,"top":0.17318435,"width":0.03656915,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":13,"bounds":{"left":0.93301195,"top":0.16400638,"width":0.0546875,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","depth":13,"bounds":{"left":0.34823802,"top":0.23782921,"width":0.053523935,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All pipelines","depth":16,"bounds":{"left":0.36186835,"top":0.24700718,"width":0.026263298,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":13,"bounds":{"left":0.40442154,"top":0.23782921,"width":0.034242023,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":16,"bounds":{"left":0.4167221,"top":0.24700718,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":13,"bounds":{"left":0.44132313,"top":0.23782921,"width":0.053025264,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All branches","depth":16,"bounds":{"left":0.45362368,"top":0.24700718,"width":0.027094414,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":13,"bounds":{"left":0.49700797,"top":0.23782921,"width":0.051030584,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cutoff date","depth":15,"bounds":{"left":0.5093085,"top":0.24700718,"width":0.025099734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":13,"bounds":{"left":0.55069816,"top":0.23782921,"width":0.043218084,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All","depth":14,"bounds":{"left":0.55502,"top":0.24700718,"width":0.0066489363,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"bounds":{"left":0.5616689,"top":0.24700718,"width":0.01861702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":13,"bounds":{"left":0.93301195,"top":0.2386273,"width":0.0546875,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Display options","depth":14,"bounds":{"left":0.94797206,"top":0.24780527,"width":0.034075797,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":14,"bounds":{"left":0.35355717,"top":0.3196329,"width":0.015292553,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"bounds":{"left":0.42603058,"top":0.3196329,"width":0.012466756,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"bounds":{"left":0.48287898,"top":0.3196329,"width":0.018284574,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"bounds":{"left":0.5728058,"top":0.3196329,"width":0.03274601,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"bounds":{"left":0.70578456,"top":0.3196329,"width":0.025764627,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":14,"bounds":{"left":0.8636968,"top":0.3196329,"width":0.009640957,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":14,"bounds":{"left":0.9019282,"top":0.3196329,"width":0.01662234,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.92918885,"top":0.3196329,"width":0.014793883,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":0.34796488,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57701","depth":12,"bounds":{"left":0.3538896,"top":0.3643256,"width":0.013297873,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57701","depth":13,"bounds":{"left":0.3538896,"top":0.36552274,"width":0.013297873,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.3499601,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"bounds":{"left":0.42802528,"top":0.35155627,"width":0.03274601,"height":0.023144454},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"bounds":{"left":0.43866357,"top":0.35634476,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14m 11s","depth":13,"bounds":{"left":0.42802528,"top":0.38028732,"width":0.017287234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"bounds":{"left":0.4453125,"top":0.38028732,"width":0.016123671,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"bounds":{"left":0.46210107,"top":0.37470073,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":0.35514766,"width":0.045711435,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":0.35594574,"width":0.045711435,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":0.34836394,"width":0.09474734,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":0.349162,"width":0.09474734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.36711892,"width":0.08992686,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"bounds":{"left":0.5724734,"top":0.36871508,"width":0.020113032,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"bounds":{"left":0.59391624,"top":0.36871508,"width":0.0625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.35594574,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.35594574,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.85056514,"top":0.34836394,"width":0.027759308,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6m ago","depth":15,"bounds":{"left":0.8562167,"top":0.3575419,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89511305,"top":0.34836394,"width":0.028424202,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.42657623,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.42603058,"top":0.42418197,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.44132313,"top":0.42657623,"width":0.03374335,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876688","depth":16,"bounds":{"left":0.47772607,"top":0.42657623,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 39s","depth":14,"bounds":{"left":0.90176195,"top":0.42418197,"width":0.016456118,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 39s","depth":15,"bounds":{"left":0.90176195,"top":0.42657623,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.44972068,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.4521149,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876692","depth":16,"bounds":{"left":0.47623006,"top":0.4521149,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"bounds":{"left":0.9019282,"top":0.44972068,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"bounds":{"left":0.9019282,"top":0.4521149,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.47525936,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.47765362,"width":0.029920213,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876693","depth":16,"bounds":{"left":0.4739029,"top":0.47765362,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 41s","depth":14,"bounds":{"left":0.9019282,"top":0.47525936,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 41s","depth":15,"bounds":{"left":0.9019282,"top":0.47765362,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"bounds":{"left":0.42603058,"top":0.5007981,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.44132313,"top":0.50319237,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876689","depth":16,"bounds":{"left":0.47623006,"top":0.50319237,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"50s","depth":14,"bounds":{"left":0.9097407,"top":0.5007981,"width":0.008477394,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"50s","depth":15,"bounds":{"left":0.9097407,"top":0.50319237,"width":0.008477394,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"bounds":{"left":0.42603058,"top":0.5263368,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.44132313,"top":0.52873105,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876690","depth":16,"bounds":{"left":0.46210107,"top":0.52873105,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"bounds":{"left":0.9019282,"top":0.5263368,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"bounds":{"left":0.9019282,"top":0.52873105,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.5518755,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.55426973,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876694","depth":16,"bounds":{"left":0.4566157,"top":0.55426973,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 28s","depth":14,"bounds":{"left":0.9019282,"top":0.5518755,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 28s","depth":15,"bounds":{"left":0.9019282,"top":0.55426973,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test","depth":14,"bounds":{"left":0.42603058,"top":0.5774142,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.44132313,"top":0.5798085,"width":0.008643617,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876695","depth":16,"bounds":{"left":0.45262632,"top":0.5798085,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 2s","depth":14,"bounds":{"left":0.90425533,"top":0.5774142,"width":0.013962766,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 2s","depth":15,"bounds":{"left":0.90425533,"top":0.5798085,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test-backend-lint","depth":14,"bounds":{"left":0.42603058,"top":0.6029529,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"bounds":{"left":0.44132313,"top":0.60534716,"width":0.038896278,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876691","depth":16,"bounds":{"left":0.48287898,"top":0.60534716,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 16s","depth":14,"bounds":{"left":0.90176195,"top":0.6029529,"width":0.016456118,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 16s","depth":15,"bounds":{"left":0.90176195,"top":0.60534716,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"bounds":{"left":0.44132313,"top":0.6308859,"width":0.02642952,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876696","depth":16,"bounds":{"left":0.47041222,"top":0.6308859,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.6715882,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.42802528,"top":0.67318434,"width":0.033410903,"height":0.022745412},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.43866357,"top":0.6775738,"width":0.018783245,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.6763767,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.6771748,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.67917,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":0.669992,"width":0.09474734,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":0.6707901,"width":0.09474734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.688747,"width":0.08992686,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"bounds":{"left":0.5724734,"top":0.6903432,"width":0.020113032,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"bounds":{"left":0.59391624,"top":0.6903432,"width":0.0625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.6771748,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.6771748,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.8507314,"top":0.669992,"width":0.027593086,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7m ago","depth":15,"bounds":{"left":0.85638297,"top":0.67877096,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89877,"top":0.669992,"width":0.024767287,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.67318434,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.67318434,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.67318434,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.67318434,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.67318434,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.73064643,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.7278532,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.73064643,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876687","depth":16,"bounds":{"left":0.4566157,"top":0.73064643,"width":0.016788565,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 1s","depth":14,"bounds":{"left":0.9055851,"top":0.7278532,"width":0.012632979,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 1s","depth":15,"bounds":{"left":0.9055851,"top":0.73064643,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":0.7801277,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57700","depth":12,"bounds":{"left":0.3538896,"top":0.7964884,"width":0.013962766,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57700","depth":13,"bounds":{"left":0.3538896,"top":0.7972865,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.7821229,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"bounds":{"left":0.42802528,"top":0.78371906,"width":0.035738032,"height":0.023144454},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"bounds":{"left":0.43866357,"top":0.7881085,"width":0.021110373,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":0.7869114,"width":0.045711435,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":0.7881085,"width":0.045711435,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":0.78052676,"width":0.09474734,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":0.7813248,"width":0.09474734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.7992817,"width":0.12765957,"height":0.033519555},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"bounds":{"left":0.5724734,"top":0.80087787,"width":0.019780586,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"bounds":{"left":0.5724734,"top":0.80087787,"width":0.12283909,"height":0.030726258},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.7881085,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.7881085,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.8484042,"top":0.78052676,"width":0.029920213,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10m ago","depth":15,"bounds":{"left":0.8540558,"top":0.7897047,"width":0.01861702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89660907,"top":0.78052676,"width":0.026928192,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.78371906,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.78371906,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.78371906,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.78371906,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.78371906,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.8579409,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.42603058,"top":0.85514766,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.44132313,"top":0.8579409,"width":0.03374335,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876678","depth":16,"bounds":{"left":0.47772607,"top":0.8579409,"width":0.016788565,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 18s","depth":14,"bounds":{"left":0.9025931,"top":0.85514766,"width":0.015625,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 18s","depth":15,"bounds":{"left":0.9025931,"top":0.8579409,"width":0.015625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.88068634,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.88347965,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876681","depth":16,"bounds":{"left":0.47623006,"top":0.88347965,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 44s","depth":14,"bounds":{"left":0.9009308,"top":0.88068634,"width":0.017287234,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 44s","depth":15,"bounds":{"left":0.9009308,"top":0.88347965,"width":0.017287234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.9062251,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.90901834,"width":0.029920213,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876682","depth":16,"bounds":{"left":0.4739029,"top":0.90901834,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":0.9062251,"width":0.005485372,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":0.90901834,"width":0.005485372,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-backend","depth":14,"bounds":{"left":0.42603058,"top":0.93176377,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.44132313,"top":0.9345571,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876679","depth":16,"bounds":{"left":0.47623006,"top":0.9345571,"width":0.016788565,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 43s","depth":14,"bounds":{"left":0.90109706,"top":0.93176377,"width":0.017121011,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 43s","depth":15,"bounds":{"left":0.90109706,"top":0.9345571,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job phpstan","depth":14,"bounds":{"left":0.42603058,"top":0.95730245,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.44132313,"top":0.96009576,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876685","depth":16,"bounds":{"left":0.46210107,"top":0.96009576,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":0.95730245,"width":0.005485372,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":0.96009576,"width":0.005485372,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"bounds":{"left":0.42603058,"top":0.9828412,"width":0.3254654,"height":0.017158806},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.9856345,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876683","depth":16,"bounds":{"left":0.4566157,"top":0.9856345,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":0.9828412,"width":0.005485372,"height":0.017158806},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":0.9856345,"width":0.005485372,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test","depth":14,"bounds":{"left":0.42603058,"top":1.0,"width":0.3254654,"height":-0.008379936},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.44132313,"top":1.0,"width":0.008643617,"height":-0.011173129},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876684","depth":16,"bounds":{"left":0.45262632,"top":1.0,"width":0.017121011,"height":-0.011173129},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.008379936},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.011173129},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-backend-lint","depth":14,"bounds":{"left":0.42603058,"top":1.0,"width":0.3254654,"height":-0.03391862},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"bounds":{"left":0.44132313,"top":1.0,"width":0.038896278,"height":-0.03671193},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876680","depth":16,"bounds":{"left":0.48287898,"top":1.0,"width":0.016954787,"height":-0.03671193},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.03391862},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.03671193},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job sonar_cloud","depth":14,"bounds":{"left":0.42603058,"top":1.0,"width":0.3254654,"height":-0.059457302},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"bounds":{"left":0.44132313,"top":1.0,"width":0.026928192,"height":-0.062250614},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876686","depth":16,"bounds":{"left":0.4709109,"top":1.0,"width":0.017121011,"height":-0.062250614},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.059457302},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"bounds":{"left":0.9127327,"top":1.0,"width":0.005485372,"height":-0.062250614},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876677","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57699","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57699","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876659","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 19s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 19s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876660","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 55s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 55s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876661","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 57s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 57s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876662","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 10s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 10s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876663","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876668","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876669","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876671","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876670","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 52s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 52s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876672","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"15s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_backend_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_backend_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876674","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5m 13s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5m 13s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876676","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_video_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_video_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876673","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"46s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"46s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_frontend_assets_to_s3_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_frontend_assets_to_s3_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876675","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876664","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876665","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876666","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job sonar_cloud","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876667","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 48s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 48s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.90143657,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.42802528,"top":0.9030327,"width":0.033410903,"height":0.022745412},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.43866357,"top":0.9074222,"width":0.018783245,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.9062251,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.90702313,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.90901834,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.90702313,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.90702313,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"25m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89660907,"top":0.89984035,"width":0.026928192,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.97725457,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.9744613,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.97725457,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876628","depth":16,"bounds":{"left":0.4566157,"top":0.97725457,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"bounds":{"left":0.9019282,"top":0.9744613,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"bounds":{"left":0.9019282,"top":0.97725457,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.00831117,"height":-0.026735783},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57698","depth":12,"bounds":{"left":0.3538896,"top":1.0,"width":0.01412899,"height":-0.043096542},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57698","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.01412899,"height":-0.04389465},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.033519506},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3ac70b3","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":1.0,"width":0.011303191,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":1.0,"width":0.034574468,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"25m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
8287808638275343091
|
866491601504859832
|
idle
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 11s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
6m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
2m 2s
2m 2s
RUNNING job test-backend-lint
test-backend-lint
876691
4m 16s
4m 16s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
7m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
8m 44s
8m 44s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
8m 43s
8m 43s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
24m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
25m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
25m ago
Copy timestamp duration to clipboard...
|
NULL
|
|
76406
|
NULL
|
0
|
2026-04-24T07:53:32.522106+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017212522_m1.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57703
57703
RUNNING workflow setup-workflow. Collapse the workflow jobs list.
Status Running Running
Running
5s
remain
Info Outline
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
b1d5c77
Merge branch 'master' into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
23s ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
RUNNING job setup
setup
876698
1m 24s
1m 24s
app
57702
57702
CANCELED workflow setup-workflow. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
deacf36
Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
1m ago
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
CANCELED job setup
setup
876697
1m 48s
1m 48s
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
9m 22s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
11m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
6m 51s
6m 51s
SUCCESS job test-backend-lint
test-backend-lint
876691
4m 12s
4m 12s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
12m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
13m 33s
13m 33s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
13m 32s
13m 32s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
15m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
28m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
30m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
29m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Home","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"bounds":{"left":0.10034722,"top":0.0,"width":0.029166667,"height":0.064444445},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"bounds":{"left":0.10034722,"top":0.0,"width":0.029166667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All pipelines","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All branches","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cutoff date","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Display options","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57703","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57703","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5s","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20372-ai-reports-promotion-pages","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20372-ai-reports-promotion-pages","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"b1d5c77","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-20372-ai-reports-promotion-pages","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"23s ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876698","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 24s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 24s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57702","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57702","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20372-ai-reports-promotion-pages","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20372-ai-reports-promotion-pages","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deacf36","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876697","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 48s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 48s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57701","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57701","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9m 22s","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"11m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876688","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876692","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876693","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 41s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 41s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876689","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"50s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"50s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876690","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876694","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 28s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 28s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876695","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"6m 51s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6m 51s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876691","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 12s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 12s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876696","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.32951388,"top":0.0,"width":0.06979167,"height":0.031666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.3517361,"top":0.0,"width":0.03923611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.44409722,"top":0.0,"width":0.07326389,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.44409722,"top":0.0,"width":0.07326389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52847224,"top":0.0,"width":0.023263888,"height":0.013888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.0,"width":0.18784723,"height":0.023333333},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"bounds":{"left":0.63125,"top":0.0,"width":0.042013887,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"bounds":{"left":0.67604166,"top":0.0,"width":0.13055556,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.0,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.0,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"12m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.0,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.32534721,"top":0.0,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.0,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876687","depth":16,"bounds":{"left":0.38923612,"top":0.0,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 1s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 1s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.17465279,"top":0.049444444,"width":0.017361112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57700","depth":12,"bounds":{"left":0.17465279,"top":0.07277778,"width":0.029166667,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57700","depth":13,"bounds":{"left":0.17465279,"top":0.07388889,"width":0.029166667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.3045139,"top":0.05277778,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"bounds":{"left":0.32951388,"top":0.055,"width":0.074652776,"height":0.031666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"bounds":{"left":0.3517361,"top":0.06111111,"width":0.044097222,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.44409722,"top":0.059444446,"width":0.09548611,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.44409722,"top":0.060555555,"width":0.09548611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.63125,"top":0.050555557,"width":0.19791667,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.63125,"top":0.051666666,"width":0.19791667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.07666667,"width":0.26666668,"height":0.046666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"bounds":{"left":0.63125,"top":0.078888886,"width":0.041319445,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"bounds":{"left":0.63125,"top":0.078888886,"width":0.25659722,"height":0.042777777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.060555555,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.060555555,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.15833333,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.32534721,"top":0.15444444,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.35729167,"top":0.15833333,"width":0.07048611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876678","depth":16,"bounds":{"left":0.43333334,"top":0.15833333,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 18s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 18s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.19,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.19388889,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876681","depth":16,"bounds":{"left":0.43020833,"top":0.19388889,"width":0.034027778,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"13m 33s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13m 33s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.22555555,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.22944444,"width":0.0625,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876682","depth":16,"bounds":{"left":0.4253472,"top":0.22944444,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-backend","depth":14,"bounds":{"left":0.32534721,"top":0.2611111,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.35729167,"top":0.265,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876679","depth":16,"bounds":{"left":0.43020833,"top":0.265,"width":0.035069443,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"13m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job phpstan","depth":14,"bounds":{"left":0.32534721,"top":0.29666665,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.35729167,"top":0.30055556,"width":0.03784722,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876685","depth":16,"bounds":{"left":0.40069443,"top":0.30055556,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"bounds":{"left":0.32534721,"top":0.33222222,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.3361111,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876683","depth":16,"bounds":{"left":0.38923612,"top":0.3361111,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test","depth":14,"bounds":{"left":0.32534721,"top":0.36777776,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.35729167,"top":0.37166667,"width":0.018055556,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876684","depth":16,"bounds":{"left":0.38090277,"top":0.37166667,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-backend-lint","depth":14,"bounds":{"left":0.32534721,"top":0.40333334,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"bounds":{"left":0.35729167,"top":0.4072222,"width":0.08125,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876680","depth":16,"bounds":{"left":0.44409722,"top":0.4072222,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job sonar_cloud","depth":14,"bounds":{"left":0.32534721,"top":0.43888888,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"bounds":{"left":0.35729167,"top":0.44277778,"width":0.05625,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876686","depth":16,"bounds":{"left":0.41909721,"top":0.44277778,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.3045139,"top":0.49888888,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.32951388,"top":0.5011111,"width":0.06979167,"height":0.032222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.3517361,"top":0.50722224,"width":0.03923611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.44409722,"top":0.50555557,"width":0.07326389,"height":0.022222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.44409722,"top":0.50722224,"width":0.07326389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52847224,"top":0.51,"width":0.023263888,"height":0.013888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.63125,"top":0.49666667,"width":0.19791667,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.63125,"top":0.4977778,"width":0.19791667,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.5227778,"width":0.26666668,"height":0.046666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"bounds":{"left":0.63125,"top":0.525,"width":0.041319445,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"bounds":{"left":0.63125,"top":0.525,"width":0.25659722,"height":0.042777777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.50722224,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.50722224,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.60444444,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.32534721,"top":0.60055554,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.60444444,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876677","depth":16,"bounds":{"left":0.38923612,"top":0.60444444,"width":0.034722224,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.17465279,"top":0.67333335,"width":0.017361112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57699","depth":12,"bounds":{"left":0.17465279,"top":0.6961111,"width":0.029513888,"height":0.022222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57699","depth":13,"bounds":{"left":0.17465279,"top":0.69777775,"width":0.029513888,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.3045139,"top":0.6761111,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.32951388,"top":0.67833334,"width":0.06979167,"height":0.032222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.3517361,"top":0.685,"width":0.03923611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.44409722,"top":0.68333334,"width":0.09548611,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.44409722,"top":0.6844444,"width":0.09548611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"bounds":{"left":0.63125,"top":0.67388886,"width":0.124305554,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"bounds":{"left":0.63125,"top":0.675,"width":0.124305554,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.63125,"top":0.7,"width":0.26666668,"height":0.046666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"bounds":{"left":0.63125,"top":0.7022222,"width":0.041666668,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"bounds":{"left":0.63125,"top":0.7022222,"width":0.18333334,"height":0.042777777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.6844444,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.6844444,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"28m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.7816667,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.32534721,"top":0.7777778,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.35729167,"top":0.7816667,"width":0.07048611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876659","depth":16,"bounds":{"left":0.43333334,"top":0.7816667,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 19s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 19s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.81333333,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.81722224,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876660","depth":16,"bounds":{"left":0.43020833,"top":0.81722224,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 55s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 55s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"bounds":{"left":0.32534721,"top":0.8488889,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.35729167,"top":0.8527778,"width":0.0625,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876661","depth":16,"bounds":{"left":0.4253472,"top":0.8527778,"width":0.034027778,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 57s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 57s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"bounds":{"left":0.32534721,"top":0.8844444,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.35729167,"top":0.8883333,"width":0.06736111,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876662","depth":16,"bounds":{"left":0.43020833,"top":0.8883333,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 10s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 10s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"bounds":{"left":0.32534721,"top":0.92,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.35729167,"top":0.92388886,"width":0.03784722,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876663","depth":16,"bounds":{"left":0.40069443,"top":0.92388886,"width":0.036111113,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.95555556,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.95944446,"width":0.15069444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876668","depth":16,"bounds":{"left":0.51354164,"top":0.95944446,"width":0.03576389,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":0.9911111,"width":0.6746528,"height":0.0088889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":0.995,"width":0.17048611,"height":0.004999995},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876669","depth":16,"bounds":{"left":0.53333336,"top":0.995,"width":0.035416666,"height":0.004999995},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":1.0,"width":0.6746528,"height":-0.026666641},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":1.0,"width":0.16215278,"height":-0.030555606},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876671","depth":16,"bounds":{"left":0.525,"top":1.0,"width":0.033680554,"height":-0.030555606},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"bounds":{"left":0.32534721,"top":1.0,"width":0.6746528,"height":-0.062222242},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"bounds":{"left":0.35729167,"top":1.0,"width":0.19166666,"height":-0.06611109},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876670","depth":16,"bounds":{"left":0.5545139,"top":1.0,"width":0.034722224,"height":-0.06611109},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 52s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 52s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"bounds":{"left":0.32534721,"top":1.0,"width":0.6746528,"height":-0.097777724},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876672","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"15s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_backend_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_backend_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876674","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5m 13s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5m 13s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876676","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_video_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_video_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876673","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"46s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"46s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_frontend_assets_to_s3_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_frontend_assets_to_s3_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876675","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876664","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876665","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876666","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job sonar_cloud","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876667","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 48s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 48s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.0,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.32534721,"top":0.0,"width":0.6746528,"height":0.026666667},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.35729167,"top":0.0,"width":0.02638889,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876628","depth":16,"bounds":{"left":0.38923612,"top":0.0,"width":0.035416666,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.17465279,"top":0.03722222,"width":0.017361112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57698","depth":12,"bounds":{"left":0.17465279,"top":0.06,"width":0.029513888,"height":0.021666666},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57698","depth":13,"bounds":{"left":0.17465279,"top":0.06111111,"width":0.029513888,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.44409722,"top":0.046666667,"width":0.09548611,"height":0.022222223},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.44409722,"top":0.048333332,"width":0.09548611,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3ac70b3","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.93680555,"top":0.048333332,"width":0.023611112,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.96319443,"top":0.048333332,"width":0.03680557,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.26944444,"top":0.14666666,"width":0.022569444,"height":0.019444445},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
301707782656552367
|
-8356600059851278672
|
idle
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57703
57703
RUNNING workflow setup-workflow. Collapse the workflow jobs list.
Status Running Running
Running
5s
remain
Info Outline
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
b1d5c77
Merge branch 'master' into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
23s ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
RUNNING job setup
setup
876698
1m 24s
1m 24s
app
57702
57702
CANCELED workflow setup-workflow. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
deacf36
Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
1m ago
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
CANCELED job setup
setup
876697
1m 48s
1m 48s
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
9m 22s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
11m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
6m 51s
6m 51s
SUCCESS job test-backend-lint
test-backend-lint
876691
4m 12s
4m 12s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
12m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
13m 33s
13m 33s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
13m 32s
13m 32s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
15m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
28m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
30m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
29m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs...
|
NULL
|
|
76407
|
NULL
|
0
|
2026-04-24T07:53:32.799287+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017212799_m2.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57703
57703
RUNNING workflow setup-workflow. Collapse the workflow jobs list.
Status Running Running
Running
5s
remain
Info Outline
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
b1d5c77
Merge branch 'master' into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
23s ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
RUNNING job setup
setup
876698
1m 24s
1m 24s
app
57702
57702
CANCELED workflow setup-workflow. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
deacf36
Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
1m ago
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
CANCELED job setup
setup
876697
1m 48s
1m 48s
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
9m 22s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
11m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
6m 51s
6m 51s
SUCCESS job test-backend-lint
test-backend-lint
876691
4m 12s
4m 12s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
12m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
13m 33s
13m 33s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
13m 32s
13m 32s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
15m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
28m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
30m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
29m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876629
1m 28s
1m 28s
SUCCESS job build-frontend
build-frontend
876633
2m 3s
2m 3s
SUCCESS job test-frontend
test-frontend
876644
1m 40s
1m 40s
SUCCESS job build-backend
build-backend
876630
1m 9s
1m 9s
SUCCESS job phpstan
phpstan
876631
1m 4s
1m 4s
SUCCESS job prepare_deploy_revision_prod
prepare_deploy_revision_prod
876646
50s
50s
SUCCESS job build_docker_backend_code_prod
build_docker_backend_code_prod
876649
1m 56s
1m 56s
SUCCESS job build_docker_worker_code_prod...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.16555852,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.23703113,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.07679521,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29837102,"top":0.3312051,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.15924202,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"bounds":{"left":0.31831783,"top":0.061452515,"width":0.044215426,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"bounds":{"left":0.9371675,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"bounds":{"left":0.9517952,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"bounds":{"left":0.96642286,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"bounds":{"left":0.98105055,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"bounds":{"left":0.3179854,"top":0.10295291,"width":0.01462766,"height":0.035115723},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Home","depth":10,"bounds":{"left":0.3159907,"top":0.15083799,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"bounds":{"left":0.31881648,"top":0.1839585,"width":0.012965426,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"bounds":{"left":0.3159907,"top":0.21308859,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"bounds":{"left":0.31499335,"top":0.2462091,"width":0.020611702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"bounds":{"left":0.3159907,"top":0.2753392,"width":0.01861702,"height":0.04668795},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"bounds":{"left":0.31632313,"top":0.3084597,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"bounds":{"left":0.3159907,"top":0.33798882,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"bounds":{"left":0.31648937,"top":0.37071028,"width":0.01761968,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"bounds":{"left":0.3159907,"top":0.40023944,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"bounds":{"left":0.31665558,"top":0.4329609,"width":0.017287234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"bounds":{"left":0.3159907,"top":0.46249002,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"bounds":{"left":0.31632313,"top":0.49561054,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"bounds":{"left":0.3159907,"top":0.52474064,"width":0.01861702,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"bounds":{"left":0.32130983,"top":0.55786115,"width":0.007978723,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"bounds":{"left":0.3159907,"top":0.58699125,"width":0.01861702,"height":0.04668795},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"bounds":{"left":0.32064494,"top":0.6201117,"width":0.00930851,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"bounds":{"left":0.31831783,"top":0.9345571,"width":0.013962766,"height":0.046288908},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"bounds":{"left":0.31831783,"top":0.96727854,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"bounds":{"left":0.34823802,"top":0.1245012,"width":0.042054523,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"bounds":{"left":0.35887632,"top":0.12609737,"width":0.030086435,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"bounds":{"left":0.3957779,"top":0.1245012,"width":0.021775266,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"bounds":{"left":0.40641624,"top":0.12609737,"width":0.009807181,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"bounds":{"left":0.35887632,"top":0.16400638,"width":0.016954787,"height":0.029130088},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.35887632,"top":0.16480447,"width":0.016954787,"height":0.027533919},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"bounds":{"left":0.34823802,"top":0.19952115,"width":0.024102394,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"bounds":{"left":0.34823802,"top":0.20151636,"width":0.024102394,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"bounds":{"left":0.3776596,"top":0.19952115,"width":0.021110373,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.3776596,"top":0.20151636,"width":0.021110373,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"bounds":{"left":0.4040891,"top":0.19952115,"width":0.020611702,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"bounds":{"left":0.4040891,"top":0.20151636,"width":0.020611702,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"bounds":{"left":0.86984706,"top":0.16400638,"width":0.057845745,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"bounds":{"left":0.88580453,"top":0.17318435,"width":0.03656915,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":13,"bounds":{"left":0.93301195,"top":0.16400638,"width":0.0546875,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","depth":13,"bounds":{"left":0.34823802,"top":0.23782921,"width":0.053523935,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All pipelines","depth":16,"bounds":{"left":0.36186835,"top":0.24700718,"width":0.026263298,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":13,"bounds":{"left":0.40442154,"top":0.23782921,"width":0.034242023,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":16,"bounds":{"left":0.4167221,"top":0.24700718,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":13,"bounds":{"left":0.44132313,"top":0.23782921,"width":0.053025264,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All branches","depth":16,"bounds":{"left":0.45362368,"top":0.24700718,"width":0.027094414,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":13,"bounds":{"left":0.49700797,"top":0.23782921,"width":0.051030584,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cutoff date","depth":15,"bounds":{"left":0.5093085,"top":0.24700718,"width":0.025099734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":13,"bounds":{"left":0.55069816,"top":0.23782921,"width":0.043218084,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All","depth":14,"bounds":{"left":0.55502,"top":0.24700718,"width":0.0066489363,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"bounds":{"left":0.5616689,"top":0.24700718,"width":0.01861702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":13,"bounds":{"left":0.93301195,"top":0.2386273,"width":0.0546875,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Display options","depth":14,"bounds":{"left":0.94797206,"top":0.24780527,"width":0.034075797,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":14,"bounds":{"left":0.35355717,"top":0.3196329,"width":0.015292553,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"bounds":{"left":0.42603058,"top":0.3196329,"width":0.012466756,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"bounds":{"left":0.48287898,"top":0.3196329,"width":0.018284574,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"bounds":{"left":0.5728058,"top":0.3196329,"width":0.03274601,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"bounds":{"left":0.70578456,"top":0.3196329,"width":0.025764627,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":14,"bounds":{"left":0.8636968,"top":0.3196329,"width":0.009640957,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":14,"bounds":{"left":0.9019282,"top":0.3196329,"width":0.01662234,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.92918885,"top":0.3196329,"width":0.014793883,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":0.34796488,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57703","depth":12,"bounds":{"left":0.3538896,"top":0.3643256,"width":0.013962766,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57703","depth":13,"bounds":{"left":0.3538896,"top":0.36552274,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.3499601,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"bounds":{"left":0.42802528,"top":0.35155627,"width":0.03274601,"height":0.023144454},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"bounds":{"left":0.43866357,"top":0.35634476,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5s","depth":13,"bounds":{"left":0.42802528,"top":0.38028732,"width":0.005319149,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"bounds":{"left":0.43334442,"top":0.38028732,"width":0.016123671,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"bounds":{"left":0.45013297,"top":0.37470073,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.35514766,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.35594574,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.35794094,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20372-ai-reports-promotion-pages","depth":13,"bounds":{"left":0.5724734,"top":0.34836394,"width":0.08693484,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20372-ai-reports-promotion-pages","depth":14,"bounds":{"left":0.5724734,"top":0.349162,"width":0.08693484,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.36711892,"width":0.12765957,"height":0.033519555},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"b1d5c77","depth":16,"bounds":{"left":0.5724734,"top":0.36871508,"width":0.019115692,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-20372-ai-reports-promotion-pages","depth":16,"bounds":{"left":0.5724734,"top":0.36871508,"width":0.11087101,"height":0.030726258},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.35594574,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.35594574,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.84923536,"top":0.34836394,"width":0.029089095,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"23s ago","depth":15,"bounds":{"left":0.85488695,"top":0.3575419,"width":0.017785905,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89611036,"top":0.34836394,"width":0.027426861,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.35155627,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.42657623,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job setup","depth":14,"bounds":{"left":0.42603058,"top":0.42418197,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.42657623,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876698","depth":16,"bounds":{"left":0.4566157,"top":0.42657623,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 24s","depth":14,"bounds":{"left":0.9019282,"top":0.42418197,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 24s","depth":15,"bounds":{"left":0.9019282,"top":0.42657623,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":0.47605747,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57702","depth":12,"bounds":{"left":0.3538896,"top":0.49281725,"width":0.013962766,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57702","depth":13,"bounds":{"left":0.3538896,"top":0.49361533,"width":0.013962766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.47845173,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"bounds":{"left":0.42802528,"top":0.48004788,"width":0.035738032,"height":0.022745412},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"bounds":{"left":0.43866357,"top":0.48443735,"width":0.021110373,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.48324022,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.4840383,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.48603353,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20372-ai-reports-promotion-pages","depth":13,"bounds":{"left":0.5724734,"top":0.47685555,"width":0.08693484,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20372-ai-reports-promotion-pages","depth":14,"bounds":{"left":0.5724734,"top":0.47765362,"width":0.08693484,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.49561054,"width":0.12765957,"height":0.033519555},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deacf36","depth":16,"bounds":{"left":0.5724734,"top":0.49720672,"width":0.01861702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages","depth":16,"bounds":{"left":0.5724734,"top":0.49720672,"width":0.108211435,"height":0.047486033},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.4840383,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.4840383,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.85123,"top":0.47685555,"width":0.027094414,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m ago","depth":15,"bounds":{"left":0.8568817,"top":0.48563448,"width":0.015791224,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.48004788,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.48004788,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.48004788,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.48004788,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.48004788,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.55426973,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"bounds":{"left":0.42603058,"top":0.5514765,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.55426973,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876697","depth":16,"bounds":{"left":0.4566157,"top":0.55426973,"width":0.01662234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 48s","depth":14,"bounds":{"left":0.90176195,"top":0.5514765,"width":0.016456118,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 48s","depth":15,"bounds":{"left":0.90176195,"top":0.55426973,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":0.603751,"width":0.00831117,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57701","depth":12,"bounds":{"left":0.3538896,"top":0.6201117,"width":0.013297873,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57701","depth":13,"bounds":{"left":0.3538896,"top":0.6209098,"width":0.013297873,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.6057462,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"bounds":{"left":0.42802528,"top":0.60734236,"width":0.03274601,"height":0.023144454},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"bounds":{"left":0.43866357,"top":0.6117318,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9m 22s","depth":13,"bounds":{"left":0.42802528,"top":0.6360734,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"bounds":{"left":0.44431517,"top":0.6360734,"width":0.016123671,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"bounds":{"left":0.46110374,"top":0.63048685,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":0.6105347,"width":0.045711435,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":0.6117318,"width":0.045711435,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":0.60415006,"width":0.09474734,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":0.6049481,"width":0.09474734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.622905,"width":0.08992686,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"bounds":{"left":0.5724734,"top":0.62450117,"width":0.020113032,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"bounds":{"left":0.59391624,"top":0.62450117,"width":0.0625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.6117318,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.6117318,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.8490692,"top":0.60415006,"width":0.02925532,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"11m ago","depth":15,"bounds":{"left":0.8547208,"top":0.61332804,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89361703,"top":0.60415006,"width":0.029920213,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.60734236,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.60734236,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.60734236,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.60734236,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.60734236,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.6823623,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"bounds":{"left":0.42603058,"top":0.67996806,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"bounds":{"left":0.44132313,"top":0.6823623,"width":0.03374335,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876688","depth":16,"bounds":{"left":0.47772607,"top":0.6823623,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 39s","depth":14,"bounds":{"left":0.90176195,"top":0.67996806,"width":0.016456118,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 39s","depth":15,"bounds":{"left":0.90176195,"top":0.6823623,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.7055068,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.70790106,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876692","depth":16,"bounds":{"left":0.47623006,"top":0.70790106,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"bounds":{"left":0.9019282,"top":0.7055068,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"bounds":{"left":0.9019282,"top":0.70790106,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"bounds":{"left":0.42603058,"top":0.7310455,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"bounds":{"left":0.44132313,"top":0.73343974,"width":0.029920213,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876693","depth":16,"bounds":{"left":0.4739029,"top":0.73343974,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 41s","depth":14,"bounds":{"left":0.9019282,"top":0.7310455,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 41s","depth":15,"bounds":{"left":0.9019282,"top":0.73343974,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"bounds":{"left":0.42603058,"top":0.7565842,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"bounds":{"left":0.44132313,"top":0.7589784,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876689","depth":16,"bounds":{"left":0.47623006,"top":0.7589784,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"50s","depth":14,"bounds":{"left":0.9097407,"top":0.7565842,"width":0.008477394,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"50s","depth":15,"bounds":{"left":0.9097407,"top":0.7589784,"width":0.008477394,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"bounds":{"left":0.42603058,"top":0.7821229,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"bounds":{"left":0.44132313,"top":0.78451717,"width":0.018118352,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876690","depth":16,"bounds":{"left":0.46210107,"top":0.78451717,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"bounds":{"left":0.9019282,"top":0.7821229,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"bounds":{"left":0.9019282,"top":0.78451717,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.8076616,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.81005585,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876694","depth":16,"bounds":{"left":0.4566157,"top":0.81005585,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 28s","depth":14,"bounds":{"left":0.9019282,"top":0.8076616,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 28s","depth":15,"bounds":{"left":0.9019282,"top":0.81005585,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job test","depth":14,"bounds":{"left":0.42603058,"top":0.83320034,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"bounds":{"left":0.44132313,"top":0.8355946,"width":0.008643617,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876695","depth":16,"bounds":{"left":0.45262632,"top":0.8355946,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"6m 51s","depth":14,"bounds":{"left":0.9019282,"top":0.83320034,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6m 51s","depth":15,"bounds":{"left":0.9019282,"top":0.8355946,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"bounds":{"left":0.42603058,"top":0.858739,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"bounds":{"left":0.44132313,"top":0.8611333,"width":0.038896278,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876691","depth":16,"bounds":{"left":0.48287898,"top":0.8611333,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 12s","depth":14,"bounds":{"left":0.9019282,"top":0.858739,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 12s","depth":15,"bounds":{"left":0.9019282,"top":0.8611333,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"bounds":{"left":0.44132313,"top":0.88667196,"width":0.02642952,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876696","depth":16,"bounds":{"left":0.47041222,"top":0.88667196,"width":0.017121011,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.9273743,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.42802528,"top":0.92897046,"width":0.033410903,"height":0.022745412},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.43866357,"top":0.9333599,"width":0.018783245,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.9321628,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.93296087,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.93495613,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":0.92577815,"width":0.09474734,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":0.9265762,"width":0.09474734,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":0.9445331,"width":0.08992686,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"84bed7b","depth":16,"bounds":{"left":0.5724734,"top":0.94573027,"width":0.020113032,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 add test coverage","depth":16,"bounds":{"left":0.59391624,"top":0.94573027,"width":0.0625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.93296087,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.93296087,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.8484042,"top":0.92577815,"width":0.029920213,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"12m ago","depth":15,"bounds":{"left":0.8540558,"top":0.9345571,"width":0.01861702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89877,"top":0.92577815,"width":0.024767287,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.92897046,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.92897046,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.92897046,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.92897046,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.92897046,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.9860335,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.98363924,"width":0.3254654,"height":0.01636076},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.9860335,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876687","depth":16,"bounds":{"left":0.4566157,"top":0.9860335,"width":0.016788565,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 1s","depth":14,"bounds":{"left":0.9055851,"top":0.98363924,"width":0.012632979,"height":0.01636076},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 1s","depth":15,"bounds":{"left":0.9055851,"top":0.9860335,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.00831117,"height":-0.035514712},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57700","depth":12,"bounds":{"left":0.3538896,"top":1.0,"width":0.013962766,"height":-0.052274585},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57700","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.013962766,"height":-0.05307257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":1.0,"width":0.010638298,"height":-0.03790903},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Canceled Canceled","depth":12,"bounds":{"left":0.42802528,"top":1.0,"width":0.035738032,"height":-0.039505243},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Canceled","depth":13,"bounds":{"left":0.43866357,"top":1.0,"width":0.021110373,"height":-0.04389465},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.04269755},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.043495655},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"bounds":{"left":0.5724734,"top":1.0,"width":0.09474734,"height":-0.03631282},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"bounds":{"left":0.5724734,"top":1.0,"width":0.09474734,"height":-0.037110925},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"bounds":{"left":0.5724734,"top":1.0,"width":0.12765957,"height":-0.055067778},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"bounds":{"left":0.5724734,"top":1.0,"width":0.019780586,"height":-0.05666399},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"bounds":{"left":0.5724734,"top":1.0,"width":0.12283909,"height":-0.05666399},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":1.0,"width":0.011303191,"height":-0.043495655},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":1.0,"width":0.034574468,"height":-0.043495655},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"bounds":{"left":0.84823805,"top":1.0,"width":0.030086435,"height":-0.03631282},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14m ago","depth":15,"bounds":{"left":0.85388964,"top":1.0,"width":0.018783245,"height":-0.04509175},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89660907,"top":1.0,"width":0.026928192,"height":-0.03631282},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":1.0,"width":0.010638298,"height":-0.039505243},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":1.0,"width":0.010638298,"height":-0.039505243},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":1.0,"width":0.010638298,"height":-0.039505243},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":1.0,"width":0.010638298,"height":-0.039505243},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":1.0,"width":0.010638298,"height":-0.039505243},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876678","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 18s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 18s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876681","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"13m 33s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13m 33s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876682","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876679","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"13m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"13m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876685","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876683","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876684","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876680","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"CANCELED job sonar_cloud","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876686","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20157-AJ-report-not-send-notification","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157-AJ-report-not-send-notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2b160b5","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20157 move user pilot tracking changes to separated PR","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876677","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"39s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"39s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57699","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57699","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"28m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876659","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 19s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 19s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876660","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 55s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 55s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876661","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 57s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 57s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876662","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 10s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 10s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876663","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 23s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 23s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876668","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876669","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876671","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876670","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 52s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 52s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876672","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"15s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_backend_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_backend_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876674","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5m 13s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5m 13s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876676","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 32s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 32s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_docker_worker_video_code_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_docker_worker_video_code_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876673","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"46s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"46s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job deploy_frontend_assets_to_s3_subenv","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"deploy_frontend_assets_to_s3_subenv","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876675","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876664","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876665","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"8m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-backend-lint","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-backend-lint","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876666","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4m 34s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4m 34s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job sonar_cloud","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonar_cloud","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876667","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 48s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 48s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow setup-workflow. Collapse the workflow jobs list.","depth":13,"bounds":{"left":0.41605717,"top":0.90143657,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"bounds":{"left":0.42802528,"top":0.9030327,"width":0.033410903,"height":0.022745412},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"bounds":{"left":0.43866357,"top":0.9074222,"width":0.018783245,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":12,"bounds":{"left":0.48287898,"top":0.9062251,"width":0.03507314,"height":0.01556265},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":13,"bounds":{"left":0.48287898,"top":0.90702313,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SETUP","depth":12,"bounds":{"left":0.52327126,"top":0.90901834,"width":0.011136968,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20489-hudges-phase2","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489-hudges-phase2","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad8c862","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20723 | add strict types to RemoveExpiredNudgesCommand","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":0.90702313,"width":0.011303191,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":0.90702313,"width":0.034574468,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"bounds":{"left":0.89660907,"top":0.89984035,"width":0.026928192,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"bounds":{"left":0.9288564,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"bounds":{"left":0.95013297,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":0.9030327,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"bounds":{"left":0.39926863,"top":0.97725457,"width":0.010804521,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job setup","depth":14,"bounds":{"left":0.42603058,"top":0.9744613,"width":0.3254654,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup","depth":15,"bounds":{"left":0.44132313,"top":0.97725457,"width":0.012632979,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876628","depth":16,"bounds":{"left":0.4566157,"top":0.97725457,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 29s","depth":14,"bounds":{"left":0.9019282,"top":0.9744613,"width":0.016289894,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 29s","depth":15,"bounds":{"left":0.9019282,"top":0.97725457,"width":0.016289894,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.00831117,"height":-0.026735783},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"57698","depth":12,"bounds":{"left":0.3538896,"top":1.0,"width":0.01412899,"height":-0.043096542},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57698","depth":13,"bounds":{"left":0.3538896,"top":1.0,"width":0.01412899,"height":-0.04389465},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Passed Success","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Success","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":12,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.033519506},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"bounds":{"left":0.48287898,"top":1.0,"width":0.045711435,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3ac70b3","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"bounds":{"left":0.71875,"top":1.0,"width":0.011303191,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"bounds":{"left":0.73138297,"top":1.0,"width":0.034574468,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29m ago","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"bounds":{"left":0.93949467,"top":1.0,"width":0.010638298,"height":-0.0303272},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"bounds":{"left":0.96077126,"top":1.0,"width":0.010638298,"height":-0.0303272},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"bounds":{"left":0.97140956,"top":1.0,"width":0.010638298,"height":-0.0303272},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876629","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 28s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 28s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876633","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 3s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 3s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876644","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 40s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 40s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876630","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 9s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 9s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876631","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 4s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 4s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_prod","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_prod","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876646","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"50s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"50s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_prod","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_prod","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"876649","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 56s","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 56s","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_prod","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
2458271650688565533
|
-8356600059851278672
|
idle
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
JY-20543 add AJ reports User pilot tracking by LakyLak · Pull Request #11932 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk
Chunk
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
57703
57703
RUNNING workflow setup-workflow. Collapse the workflow jobs list.
Status Running Running
Running
5s
remain
Info Outline
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
b1d5c77
Merge branch 'master' into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
23s ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
RUNNING job setup
setup
876698
1m 24s
1m 24s
app
57702
57702
CANCELED workflow setup-workflow. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
setup-workflow
setup-workflow
SETUP
JY-20372-ai-reports-promotion-pages
JY-20372-ai-reports-promotion-pages
Open commit on version control site
deacf36
Merge branch 'JY-20372-ai-reports-promotion-pages' of github.com:jiminny/app into JY-20372-ai-reports-promotion-pages
Push
Commit pushed
Copy timestamp to clipboard
1m ago
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
CANCELED job setup
setup
876697
1m 48s
1m 48s
app
57701
57701
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
9m 22s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
11m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876688
1m 39s
1m 39s
SUCCESS job build-frontend
build-frontend
876692
1m 29s
1m 29s
SUCCESS job test-frontend
test-frontend
876693
2m 41s
2m 41s
SUCCESS job build-backend
build-backend
876689
50s
50s
SUCCESS job phpstan
phpstan
876690
1m 23s
1m 23s
SUCCESS job setup
setup
876694
1m 28s
1m 28s
RUNNING job test
test
876695
6m 51s
6m 51s
SUCCESS job test-backend-lint
test-backend-lint
876691
4m 12s
4m 12s
sonar_cloud
876696
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
84bed7b
JY-20157 add test coverage
Push
Commit pushed
Copy timestamp to clipboard
12m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876687
1m 1s
1m 1s
app
57700
57700
CANCELED workflow build_accept_deploy. Collapse the workflow jobs list.
Status Canceled Canceled
Canceled
build_accept_deploy
build_accept_deploy
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
14m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876678
1m 18s
1m 18s
CANCELED job build-frontend
build-frontend
876681
13m 33s
13m 33s
CANCELED job test-frontend
test-frontend
876682
0s
0s
CANCELED job build-backend
build-backend
876679
13m 32s
13m 32s
CANCELED job phpstan
phpstan
876685
0s
0s
CANCELED job setup
setup
876683
0s
0s
CANCELED job test
test
876684
0s
0s
CANCELED job test-backend-lint
test-backend-lint
876680
0s
0s
CANCELED job sonar_cloud
sonar_cloud
876686
0s
0s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20157-AJ-report-not-send-notification
JY-20157-AJ-report-not-send-notification
Open commit on version control site
2b160b5
JY-20157 move user pilot tracking changes to separated PR
Push
Commit pushed
Copy timestamp to clipboard
15m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876677
39s
39s
app
57699
57699
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
28m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876659
1m 19s
1m 19s
SUCCESS job build-frontend
build-frontend
876660
1m 55s
1m 55s
SUCCESS job test-frontend
test-frontend
876661
1m 57s
1m 57s
SUCCESS job build-backend
build-backend
876662
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
876663
1m 23s
1m 23s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
876668
1m 4s
1m 4s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
876669
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
876671
1m 56s
1m 56s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
876670
1m 52s
1m 52s
SUCCESS job db_migrations_subenv
db_migrations_subenv
876672
15s
15s
SUCCESS job deploy_docker_backend_code_subenv
deploy_docker_backend_code_subenv
876674
5m 13s
5m 13s
SUCCESS job deploy_docker_worker_code_subenv
deploy_docker_worker_code_subenv
876676
1m 32s
1m 32s
SUCCESS job deploy_docker_worker_video_code_subenv
deploy_docker_worker_video_code_subenv
876673
46s
46s
SUCCESS job deploy_frontend_assets_to_s3_subenv
deploy_frontend_assets_to_s3_subenv
876675
1m 4s
1m 4s
SUCCESS job setup
setup
876664
58s
58s
SUCCESS job test
test
876665
8m 34s
8m 34s
SUCCESS job test-backend-lint
test-backend-lint
876666
4m 34s
4m 34s
SUCCESS job sonar_cloud
sonar_cloud
876667
1m 48s
1m 48s
SUCCESS workflow setup-workflow. Collapse the workflow jobs list.
Status Passed Success
Success
setup-workflow
setup-workflow
SETUP
JY-20489-hudges-phase2
JY-20489-hudges-phase2
Open commit on version control site
ad8c862
JY-20723 | add strict types to RemoveExpiredNudgesCommand
Push
Commit pushed
Copy timestamp to clipboard
30m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job setup
setup
876628
1m 29s
1m 29s
app
57698
57698
SUCCESS workflow build_accept_deploy. Collapse the workflow jobs list.
Status Passed Success
Success
build_accept_deploy
build_accept_deploy
master
master
Open commit on version control site
3ac70b3
Merge pull request #12012 from jiminny/JY-20735-remove-code-switching-assembly-prompt
Push
Commit pushed
Copy timestamp to clipboard
29m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
876629
1m 28s
1m 28s
SUCCESS job build-frontend
build-frontend
876633
2m 3s
2m 3s
SUCCESS job test-frontend
test-frontend
876644
1m 40s
1m 40s
SUCCESS job build-backend
build-backend
876630
1m 9s
1m 9s
SUCCESS job phpstan
phpstan
876631
1m 4s
1m 4s
SUCCESS job prepare_deploy_revision_prod
prepare_deploy_revision_prod
876646
50s
50s
SUCCESS job build_docker_backend_code_prod
build_docker_backend_code_prod
876649
1m 56s
1m 56s
SUCCESS job build_docker_worker_code_prod...
|
NULL
|
|
76450
|
NULL
|
0
|
2026-04-24T07:58:55.857688+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017535857_m1.jpg...
|
Firefox
|
JY-9712 | Nuges to expire after one year by nikola JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11981
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Close tab
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (32)
Security and quality
(
32
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Review requested
Review requested
nikolaybiaivanov
nikolaybiaivanov
requested your review on this pull request.
Add your review
Add your review
JY-9712 | Nuges to expire after one year #11981 Edit title
JY-9712 | Nuges to expire after one year
#
11981
Edit title
Unable to merge
Unable to merge
Code
Code
Open
nikolaybiaivanov
nikolaybiaivanov
wants to merge 14 commits into
master
master
from
JY-9712-change-forever-nudges-to-1-year-expiration
JY-9712-change-forever-nudges-to-1-year-expiration
Copy head branch name to clipboard
Lines changed: 1276 additions & 1668 deletions
Conversation (11)
Conversation
(
11
)
Commits (14)
Commits
(
14
)
Checks (3)
Checks
(
3
)
Files changed (33)
Files changed
(
33
)
Conversation
Conversation
@nikolaybiaivanov
Show options
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
JIRA: JY-9712
JIRA:
JY-9712
JY-9712
Deployment notes:
Deployment notes:
None
Add or remove reactions
@nikolaybiaivanov
Show options
Author
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
@claude
@claude
Add or remove reactions
react with eyes
👀
1
@claude
Show options
claude Bot commented last week •
claude
claude
Bot
commented
last week
last week
•
edited
edited
Claude finished
@nikolaybiaivanov
@nikolaybiaivanov
's task in 2m 9s
——
View job
View job
Code Review
Code Review
Completed task
Gather context and read changed files
Completed task
Review NudgeFactory.php changes
Completed task
Review NudgeRepository.php changes
Completed task
Review RemoveExpiredNudgesCommand.php changes
Completed task
Review SendNudgeExpirationWarningsCommand.php (new)
Completed task
Review NudgeController.php changes
Completed task
Review Nudge.php model changes
Completed task
Review NudgeExpirationWarningNotification.php (new)
Completed task
Review migration file (new)
Completed task
Review email templates (new)
Completed task
Review Kernel.php changes
Completed task
Post final review
Overall this is a well-structured refactor. The removal of the legacy
expires_in
integer enum in favour of a real datetime
expires_at
, the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:
1. Migration: per-row UPDATE is slow at scale
1. Migration: per-row UPDATE is slow at scale
database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php
The migration issues one
UPDATE
per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:
--
Nudges older than 1 year → expire in 8 days
UPDATE
nudges
SET
expires_at
=
DATE_ADD(NOW(), INTERVAL
8
DAY)
WHERE
expires_at IS
NULL
AND
created_at
<
DATE_SUB(NOW(), INTERVAL
1
YEAR);
--
Newer nudges → expire 1 year after creation
UPDATE
nudges
SET
expires_at
=
DATE_ADD(created_at, INTERVAL
1
YEAR)
WHERE
expires_at IS
NULL
AND
created_at
>=
DATE_SUB(NOW(), INTERVAL
1
YEAR);
Copy
The
endOfDay()
adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single
whereIn
on IDs per chunk rather than one query per row.
Fix this →
Fix this →
2. NudgeExpirationWarningNotification — side-effect in via()
2.
NudgeExpirationWarningNotification
— side-effect in
via()
app/Notifications/NudgeExpirationWarningNotification.php:15–29
$formattedExpiresAt
is set in
via()
and consumed in
toPostmark()
. This creates an implicit ordering dependency. Laravel does call
via()
first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into
toPostmark()
(or a private helper called from there) to make it self-contained:
public
function
toPostmark
():
EmailWithTemplate
{
$
email
=
new
EmailWithTemplate
(
'
nudge-expiration-warning
'
);
$
search
=
$
this
->
nudge
->
getActivitySearch
();
$
expiresAt
=
$
this
->
nudge
->
getExpiresAt
();
$
email
->
setData
([
'
nudge_name
'
=>
$
search
->
getName
(),
'
expires_at
'
=>
$
expiresAt
->
format
(
'
F j, Y
'
),
// timezone formatting can be passed separately
'
search_url
'
=>
route
(
'
show.ondemand.page
'
),
]);
return
$
email
;
}
Copy
Fix this →
Fix this →
3. squashNudgeRuns semantics change
3.
squashNudgeRuns
semantics change
app/Console/Commands/RemoveExpiredNudgesCommand.php:95
The condition changed from
whereNull('expires_at')
(only "never-expiring" nudges) to
where('expires_at', '>', now())
(all active nudges). Since nudges no longer have a "never expire" option this makes sense, but it's worth confirming: previously only nudges that had
expires_in = EXPIRE_NEVER
were squashed, now
all active nudges
are candidates. If that's intentional, a short comment explaining the rationale would help future readers.
4. SendNudgeExpirationWarningsCommand — missing Sentry capture
4.
SendNudgeExpirationWarningsCommand
— missing Sentry capture
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64
RemoveExpiredNudgesCommand
reports exceptions to Sentry;
SendNudgeExpirationWarningsCommand
only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding
Sentry::captureException($e)
in the
catch
block, consistent with the sibling command.
Fix this →
Fix this →
5. Minor — Command::SUCCESS constant
5. Minor —...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (32)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"32","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Review requested","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Review requested","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"requested your review on this pull request.","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Add your review","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add your review","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JY-9712 | Nuges to expire after one year #11981 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11981","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unable to merge","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unable to merge","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 14 commits into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-9712-change-forever-nudges-to-1-year-expiration","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712-change-forever-nudges-to-1-year-expiration","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 1276 additions & 1668 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (11)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (14)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (33)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"nikolaybiaivanov commented last week","depth":14,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-9712","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-9712","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Deployment notes:","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deployment notes:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":16,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"@nikolaybiaivanov","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"nikolaybiaivanov commented last week","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@claude","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@claude","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":15,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"react with eyes","depth":14,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"👀","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@claude","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"claude Bot commented last week •","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"claude","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"claude","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"edited","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"edited","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude finished","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@nikolaybiaivanov","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s task in 2m 9s","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"——","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View job","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View job","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gather context and read changed files","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeFactory.php changes","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeRepository.php changes","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review RemoveExpiredNudgesCommand.php changes","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review SendNudgeExpirationWarningsCommand.php (new)","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeController.php changes","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review Nudge.php model changes","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeExpirationWarningNotification.php (new)","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.4375,"top":0.0,"width":0.009722223,"height":0.015555556},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review migration file (new)","depth":18,"bounds":{"left":0.44930556,"top":0.0,"width":0.124305554,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.4375,"top":0.0,"width":0.009722223,"height":0.015555556},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review email templates (new)","depth":18,"bounds":{"left":0.44930556,"top":0.0,"width":0.13645834,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.4375,"top":0.0,"width":0.009722223,"height":0.015555556},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review Kernel.php changes","depth":18,"bounds":{"left":0.44930556,"top":0.0,"width":0.12638889,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.4375,"top":0.0,"width":0.009722223,"height":0.015555556},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Post final review","depth":18,"bounds":{"left":0.44930556,"top":0.0,"width":0.07604167,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overall this is a well-structured refactor. The removal of the legacy","depth":17,"bounds":{"left":0.43263888,"top":0.075,"width":0.30173612,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_in","depth":18,"bounds":{"left":0.7375,"top":0.07777778,"width":0.05,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"integer enum in favour of a real datetime","depth":17,"bounds":{"left":0.43263888,"top":0.075,"width":0.50069445,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":18,"bounds":{"left":0.478125,"top":0.101111114,"width":0.049652778,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:","depth":17,"bounds":{"left":0.43263888,"top":0.09833334,"width":0.5121528,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Migration: per-row UPDATE is slow at scale","depth":16,"bounds":{"left":0.43263888,"top":0.2,"width":0.5375,"height":0.02388889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Migration: per-row UPDATE is slow at scale","depth":17,"bounds":{"left":0.43263888,"top":0.2,"width":0.2576389,"height":0.023333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php","depth":18,"bounds":{"left":0.4357639,"top":0.24666667,"width":0.403125,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The migration issues one","depth":17,"bounds":{"left":0.43263888,"top":0.285,"width":0.114930555,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":18,"bounds":{"left":0.55104166,"top":0.28777778,"width":0.029861111,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:","depth":17,"bounds":{"left":0.43263888,"top":0.285,"width":0.5361111,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":17,"bounds":{"left":0.44375,"top":0.36666667,"width":0.009722223,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Nudges older than 1 year → expire in 8 days","depth":17,"bounds":{"left":0.45347223,"top":0.36666667,"width":0.21909723,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":17,"bounds":{"left":0.44375,"top":0.3861111,"width":0.029861111,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":17,"bounds":{"left":0.47361112,"top":0.3861111,"width":0.034722224,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SET","depth":17,"bounds":{"left":0.44375,"top":0.405,"width":0.014930556,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"bounds":{"left":0.45868057,"top":0.405,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"bounds":{"left":0.51840276,"top":0.405,"width":0.0048611113,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_ADD(NOW(), INTERVAL","depth":17,"bounds":{"left":0.5232639,"top":0.405,"width":0.12951389,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":17,"bounds":{"left":0.6527778,"top":0.405,"width":0.0048611113,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DAY)","depth":17,"bounds":{"left":0.6576389,"top":0.405,"width":0.025,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WHERE","depth":17,"bounds":{"left":0.44375,"top":0.42444444,"width":0.024652777,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at IS","depth":17,"bounds":{"left":0.46840277,"top":0.42444444,"width":0.074652776,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":17,"bounds":{"left":0.54305553,"top":0.42444444,"width":0.02013889,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AND","depth":17,"bounds":{"left":0.45347223,"top":0.44333333,"width":0.014930556,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"created_at","depth":17,"bounds":{"left":0.46840277,"top":0.44333333,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"<","depth":17,"bounds":{"left":0.528125,"top":0.44333333,"width":0.0052083335,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_SUB(NOW(), INTERVAL","depth":17,"bounds":{"left":0.53333336,"top":0.44333333,"width":0.12916666,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"bounds":{"left":0.6625,"top":0.44333333,"width":0.0052083335,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR);","depth":17,"bounds":{"left":0.66770834,"top":0.44333333,"width":0.034722224,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":17,"bounds":{"left":0.44375,"top":0.48166665,"width":0.009722223,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Newer nudges → expire 1 year after creation","depth":17,"bounds":{"left":0.45347223,"top":0.48166665,"width":0.21909723,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":17,"bounds":{"left":0.44375,"top":0.5011111,"width":0.029861111,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":17,"bounds":{"left":0.47361112,"top":0.5011111,"width":0.034722224,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SET","depth":17,"bounds":{"left":0.44375,"top":0.52,"width":0.014930556,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"bounds":{"left":0.45868057,"top":0.52,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"bounds":{"left":0.51840276,"top":0.52,"width":0.0048611113,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_ADD(created_at, INTERVAL","depth":17,"bounds":{"left":0.5232639,"top":0.52,"width":0.15416667,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"bounds":{"left":0.67743057,"top":0.52,"width":0.0052083335,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR)","depth":17,"bounds":{"left":0.6826389,"top":0.52,"width":0.029861111,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WHERE","depth":17,"bounds":{"left":0.44375,"top":0.53944445,"width":0.024652777,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at IS","depth":17,"bounds":{"left":0.46840277,"top":0.53944445,"width":0.074652776,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":17,"bounds":{"left":0.54305553,"top":0.53944445,"width":0.02013889,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AND","depth":17,"bounds":{"left":0.45347223,"top":0.55833334,"width":0.014930556,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"created_at","depth":17,"bounds":{"left":0.46840277,"top":0.55833334,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":">=","depth":17,"bounds":{"left":0.528125,"top":0.55833334,"width":0.010069445,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_SUB(NOW(), INTERVAL","depth":17,"bounds":{"left":0.5381944,"top":0.55833334,"width":0.12951389,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"bounds":{"left":0.66770834,"top":0.55833334,"width":0.0048611113,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR);","depth":17,"bounds":{"left":0.67256945,"top":0.55833334,"width":0.034722224,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"bounds":{"left":0.9409722,"top":0.3561111,"width":0.023611112,"height":0.039444443},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"The","depth":17,"bounds":{"left":0.43263888,"top":0.61388886,"width":0.019791666,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"endOfDay()","depth":18,"bounds":{"left":0.45555556,"top":0.6166667,"width":0.05,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single","depth":17,"bounds":{"left":0.43263888,"top":0.61388886,"width":0.528125,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereIn","depth":18,"bounds":{"left":0.7986111,"top":0.64,"width":0.035069443,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"on IDs per chunk rather than one query per row.","depth":17,"bounds":{"left":0.43263888,"top":0.63722223,"width":0.53506947,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix this →","depth":17,"bounds":{"left":0.43263888,"top":0.70166665,"width":0.043055557,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"bounds":{"left":0.43263888,"top":0.70166665,"width":0.043055557,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. NudgeExpirationWarningNotification — side-effect in via()","depth":16,"bounds":{"left":0.43263888,"top":0.78,"width":0.5375,"height":0.025},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.","depth":17,"bounds":{"left":0.43263888,"top":0.78055555,"width":0.013888889,"height":0.023333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NudgeExpirationWarningNotification","depth":18,"bounds":{"left":0.44895834,"top":0.7811111,"width":0.24861111,"height":0.023333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— side-effect in","depth":17,"bounds":{"left":0.7,"top":0.78055555,"width":0.09652778,"height":0.023333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"bounds":{"left":0.79895836,"top":0.7811111,"width":0.036805555,"height":0.023333333},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Notifications/NudgeExpirationWarningNotification.php:15–29","depth":18,"bounds":{"left":0.4357639,"top":0.8277778,"width":0.30868056,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$formattedExpiresAt","depth":18,"bounds":{"left":0.4357639,"top":0.8688889,"width":0.094444446,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is set in","depth":17,"bounds":{"left":0.53368056,"top":0.8661111,"width":0.039930556,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"bounds":{"left":0.57708335,"top":0.8688889,"width":0.024652777,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and consumed in","depth":17,"bounds":{"left":0.60520834,"top":0.8661111,"width":0.08229167,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark()","depth":18,"bounds":{"left":0.690625,"top":0.8688889,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". This creates an implicit ordering dependency. Laravel does call","depth":17,"bounds":{"left":0.43263888,"top":0.8661111,"width":0.5309028,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"bounds":{"left":0.51319444,"top":0.8922222,"width":0.025,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into","depth":17,"bounds":{"left":0.43263888,"top":0.8894445,"width":0.5072917,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark()","depth":18,"bounds":{"left":0.52881944,"top":0.91555554,"width":0.059722222,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(or a private helper called from there) to make it self-contained:","depth":17,"bounds":{"left":0.5920139,"top":0.9127778,"width":0.28784722,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public","depth":17,"bounds":{"left":0.44375,"top":0.97055554,"width":0.029861111,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"function","depth":17,"bounds":{"left":0.47847223,"top":0.97055554,"width":0.039930556,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark","depth":17,"bounds":{"left":0.5232639,"top":0.97055554,"width":0.049652778,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"():","depth":17,"bounds":{"left":0.5729167,"top":0.97055554,"width":0.02013889,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EmailWithTemplate","depth":17,"bounds":{"left":0.59305555,"top":0.97055554,"width":0.084375,"height":0.016111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":17,"bounds":{"left":0.44375,"top":0.99,"width":0.019791666,"height":0.00999999},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.46354166,"top":1.0,"width":0.0048611113,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"bounds":{"left":0.46840277,"top":1.0,"width":0.025,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"bounds":{"left":0.49340278,"top":1.0,"width":0.014930556,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new","depth":17,"bounds":{"left":0.5083333,"top":1.0,"width":0.014930556,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EmailWithTemplate","depth":17,"bounds":{"left":0.528125,"top":1.0,"width":0.08472222,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"bounds":{"left":0.6128472,"top":1.0,"width":0.0048611113,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"bounds":{"left":0.6177083,"top":1.0,"width":0.0052083335,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge-expiration-warning","depth":17,"bounds":{"left":0.62291664,"top":1.0,"width":0.119444445,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"bounds":{"left":0.7423611,"top":1.0,"width":0.0048611113,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":17,"bounds":{"left":0.44375,"top":1.0,"width":0.31354168,"height":-0.008888841},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.46354166,"top":1.0,"width":0.0048611113,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search","depth":17,"bounds":{"left":0.46840277,"top":1.0,"width":0.029861111,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"bounds":{"left":0.4982639,"top":1.0,"width":0.014930556,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.51319444,"top":1.0,"width":0.0052083335,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":17,"bounds":{"left":0.51840276,"top":1.0,"width":0.019791666,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"bounds":{"left":0.5381944,"top":1.0,"width":0.010069445,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge","depth":17,"bounds":{"left":0.5482639,"top":1.0,"width":0.024652777,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"bounds":{"left":0.5729167,"top":1.0,"width":0.010069445,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getActivitySearch","depth":17,"bounds":{"left":0.5829861,"top":1.0,"width":0.08472222,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"();","depth":17,"bounds":{"left":0.44375,"top":1.0,"width":0.23888889,"height":-0.028333306},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.46354166,"top":1.0,"width":0.0048611113,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expiresAt","depth":17,"bounds":{"left":0.46840277,"top":1.0,"width":0.044791665,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"bounds":{"left":0.51319444,"top":1.0,"width":0.014930556,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.528125,"top":1.0,"width":0.0052083335,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":17,"bounds":{"left":0.53333336,"top":1.0,"width":0.019791666,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"bounds":{"left":0.553125,"top":1.0,"width":0.010069445,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge","depth":17,"bounds":{"left":0.56319445,"top":1.0,"width":0.024652777,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"bounds":{"left":0.58784723,"top":1.0,"width":0.010069445,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getExpiresAt","depth":17,"bounds":{"left":0.59791666,"top":1.0,"width":0.059722222,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"();","depth":17,"bounds":{"left":0.44375,"top":1.0,"width":0.22881944,"height":-0.047222257},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"bounds":{"left":0.46354166,"top":1.0,"width":0.0048611113,"height":-0.08555555},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"bounds":{"left":0.46840277,"top":1.0,"width":0.025,"height":-0.08555555},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"bounds":{"left":0.49340278,"top":1.0,"width":0.010069445,"height":-0.08555555},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setData","depth":17,"bounds":{"left":0.5034722,"top":1.0,"width":0.034722224,"height":-0.08555555},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"([","depth":17,"bounds":{"left":0.44375,"top":1.0,"width":0.10451389,"height":-0.08555555},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge_name","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getName","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(),","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expiresAt","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"format","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"F j, Y","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"),","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// timezone formatting can be passed separately","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search_url","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"route","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"show.ondemand.page","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"),\n ]);","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";\n}","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"bounds":{"left":0.9409722,"top":0.96055555,"width":0.023611112,"height":0.039444443},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Fix this →","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. squashNudgeRuns semantics change","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"squashNudgeRuns","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"semantics change","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Console/Commands/RemoveExpiredNudgesCommand.php:95","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The condition changed from","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNull('expires_at')","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(only \"never-expiring\" nudges) to","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"where('expires_at', '>', now())","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(all active nudges). Since nudges no longer have a \"never expire\" option this makes sense, but it's worth confirming: previously only nudges that had","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_in = EXPIRE_NEVER","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"were squashed, now","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"all active nudges","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are candidates. If that's intentional, a short comment explaining the rationale would help future readers.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. SendNudgeExpirationWarningsCommand — missing Sentry capture","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SendNudgeExpirationWarningsCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— missing Sentry capture","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RemoveExpiredNudgesCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reports exceptions to Sentry;","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SendNudgeExpirationWarningsCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sentry::captureException($e)","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"catch","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"block, consistent with the sibling command.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix this →","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. Minor — Command::SUCCESS constant","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5. Minor —","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
2396763785837227766
|
2046170190658823097
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Close tab
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (32)
Security and quality
(
32
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Review requested
Review requested
nikolaybiaivanov
nikolaybiaivanov
requested your review on this pull request.
Add your review
Add your review
JY-9712 | Nuges to expire after one year #11981 Edit title
JY-9712 | Nuges to expire after one year
#
11981
Edit title
Unable to merge
Unable to merge
Code
Code
Open
nikolaybiaivanov
nikolaybiaivanov
wants to merge 14 commits into
master
master
from
JY-9712-change-forever-nudges-to-1-year-expiration
JY-9712-change-forever-nudges-to-1-year-expiration
Copy head branch name to clipboard
Lines changed: 1276 additions & 1668 deletions
Conversation (11)
Conversation
(
11
)
Commits (14)
Commits
(
14
)
Checks (3)
Checks
(
3
)
Files changed (33)
Files changed
(
33
)
Conversation
Conversation
@nikolaybiaivanov
Show options
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
JIRA: JY-9712
JIRA:
JY-9712
JY-9712
Deployment notes:
Deployment notes:
None
Add or remove reactions
@nikolaybiaivanov
Show options
Author
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
@claude
@claude
Add or remove reactions
react with eyes
👀
1
@claude
Show options
claude Bot commented last week •
claude
claude
Bot
commented
last week
last week
•
edited
edited
Claude finished
@nikolaybiaivanov
@nikolaybiaivanov
's task in 2m 9s
——
View job
View job
Code Review
Code Review
Completed task
Gather context and read changed files
Completed task
Review NudgeFactory.php changes
Completed task
Review NudgeRepository.php changes
Completed task
Review RemoveExpiredNudgesCommand.php changes
Completed task
Review SendNudgeExpirationWarningsCommand.php (new)
Completed task
Review NudgeController.php changes
Completed task
Review Nudge.php model changes
Completed task
Review NudgeExpirationWarningNotification.php (new)
Completed task
Review migration file (new)
Completed task
Review email templates (new)
Completed task
Review Kernel.php changes
Completed task
Post final review
Overall this is a well-structured refactor. The removal of the legacy
expires_in
integer enum in favour of a real datetime
expires_at
, the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:
1. Migration: per-row UPDATE is slow at scale
1. Migration: per-row UPDATE is slow at scale
database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php
The migration issues one
UPDATE
per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:
--
Nudges older than 1 year → expire in 8 days
UPDATE
nudges
SET
expires_at
=
DATE_ADD(NOW(), INTERVAL
8
DAY)
WHERE
expires_at IS
NULL
AND
created_at
<
DATE_SUB(NOW(), INTERVAL
1
YEAR);
--
Newer nudges → expire 1 year after creation
UPDATE
nudges
SET
expires_at
=
DATE_ADD(created_at, INTERVAL
1
YEAR)
WHERE
expires_at IS
NULL
AND
created_at
>=
DATE_SUB(NOW(), INTERVAL
1
YEAR);
Copy
The
endOfDay()
adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single
whereIn
on IDs per chunk rather than one query per row.
Fix this →
Fix this →
2. NudgeExpirationWarningNotification — side-effect in via()
2.
NudgeExpirationWarningNotification
— side-effect in
via()
app/Notifications/NudgeExpirationWarningNotification.php:15–29
$formattedExpiresAt
is set in
via()
and consumed in
toPostmark()
. This creates an implicit ordering dependency. Laravel does call
via()
first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into
toPostmark()
(or a private helper called from there) to make it self-contained:
public
function
toPostmark
():
EmailWithTemplate
{
$
email
=
new
EmailWithTemplate
(
'
nudge-expiration-warning
'
);
$
search
=
$
this
->
nudge
->
getActivitySearch
();
$
expiresAt
=
$
this
->
nudge
->
getExpiresAt
();
$
email
->
setData
([
'
nudge_name
'
=>
$
search
->
getName
(),
'
expires_at
'
=>
$
expiresAt
->
format
(
'
F j, Y
'
),
// timezone formatting can be passed separately
'
search_url
'
=>
route
(
'
show.ondemand.page
'
),
]);
return
$
email
;
}
Copy
Fix this →
Fix this →
3. squashNudgeRuns semantics change
3.
squashNudgeRuns
semantics change
app/Console/Commands/RemoveExpiredNudgesCommand.php:95
The condition changed from
whereNull('expires_at')
(only "never-expiring" nudges) to
where('expires_at', '>', now())
(all active nudges). Since nudges no longer have a "never expire" option this makes sense, but it's worth confirming: previously only nudges that had
expires_in = EXPIRE_NEVER
were squashed, now
all active nudges
are candidates. If that's intentional, a short comment explaining the rationale would help future readers.
4. SendNudgeExpirationWarningsCommand — missing Sentry capture
4.
SendNudgeExpirationWarningsCommand
— missing Sentry capture
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64
RemoveExpiredNudgesCommand
reports exceptions to Sentry;
SendNudgeExpirationWarningsCommand
only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding
Sentry::captureException($e)
in the
catch
block, consistent with the sibling command.
Fix this →
Fix this →
5. Minor — Command::SUCCESS constant
5. Minor —...
|
NULL
|
|
76451
|
NULL
|
0
|
2026-04-24T07:58:55.930027+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017535930_m2.jpg...
|
Firefox
|
JY-9712 | Nuges to expire after one year by nikola JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11981
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Close tab
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (32)
Security and quality
(
32
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Review requested
Review requested
nikolaybiaivanov
nikolaybiaivanov
requested your review on this pull request.
Add your review
Add your review
JY-9712 | Nuges to expire after one year #11981 Edit title
JY-9712 | Nuges to expire after one year
#
11981
Edit title
Unable to merge
Unable to merge
Code
Code
Open
nikolaybiaivanov
nikolaybiaivanov
wants to merge 14 commits into
master
master
from
JY-9712-change-forever-nudges-to-1-year-expiration
JY-9712-change-forever-nudges-to-1-year-expiration
Copy head branch name to clipboard
Lines changed: 1276 additions & 1668 deletions
Conversation (11)
Conversation
(
11
)
Commits (14)
Commits
(
14
)
Checks (3)
Checks
(
3
)
Files changed (33)
Files changed
(
33
)
Conversation
Conversation
@nikolaybiaivanov
Show options
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
JIRA: JY-9712
JIRA:
JY-9712
JY-9712
Deployment notes:
Deployment notes:
None
Add or remove reactions
@nikolaybiaivanov
Show options
Author
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
@claude
@claude
Add or remove reactions
react with eyes
👀
1
@claude
Show options
claude Bot commented last week •
claude
claude
Bot
commented
last week
last week
•
edited
edited
Claude finished
@nikolaybiaivanov
@nikolaybiaivanov
's task in 2m 9s
——
View job
View job
Code Review
Code Review
Completed task
Gather context and read changed files
Completed task
Review NudgeFactory.php changes
Completed task
Review NudgeRepository.php changes
Completed task
Review RemoveExpiredNudgesCommand.php changes
Completed task
Review SendNudgeExpirationWarningsCommand.php (new)
Completed task
Review NudgeController.php changes
Completed task
Review Nudge.php model changes
Completed task
Review NudgeExpirationWarningNotification.php (new)
Completed task
Review migration file (new)
Completed task
Review email templates (new)
Completed task
Review Kernel.php changes
Completed task
Post final review
Overall this is a well-structured refactor. The removal of the legacy
expires_in
integer enum in favour of a real datetime
expires_at
, the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:
1. Migration: per-row UPDATE is slow at scale
1. Migration: per-row UPDATE is slow at scale
database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php
The migration issues one
UPDATE
per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:
--
Nudges older than 1 year → expire in 8 days
UPDATE
nudges
SET
expires_at
=
DATE_ADD(NOW(), INTERVAL
8
DAY)
WHERE
expires_at IS
NULL
AND
created_at
<
DATE_SUB(NOW(), INTERVAL
1
YEAR);
--
Newer nudges → expire 1 year after creation
UPDATE
nudges
SET
expires_at
=
DATE_ADD(created_at, INTERVAL
1
YEAR)
WHERE
expires_at IS
NULL
AND
created_at
>=
DATE_SUB(NOW(), INTERVAL
1
YEAR);
Copy
The
endOfDay()
adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single
whereIn
on IDs per chunk rather than one query per row.
Fix this →
Fix this →
2. NudgeExpirationWarningNotification — side-effect in via()
2.
NudgeExpirationWarningNotification
— side-effect in
via()
app/Notifications/NudgeExpirationWarningNotification.php:15–29
$formattedExpiresAt
is set in
via()
and consumed in
toPostmark()
. This creates an implicit ordering dependency. Laravel does call
via()
first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into
toPostmark()
(or a private helper called from there) to make it self-contained:
public
function
toPostmark
():
EmailWithTemplate
{
$
email
=
new
EmailWithTemplate
(
'
nudge-expiration-warning
'
);
$
search
=
$
this
->
nudge
->
getActivitySearch
();
$
expiresAt
=
$
this
->
nudge
->
getExpiresAt
();
$
email
->
setData
([
'
nudge_name
'
=>
$
search
->
getName
(),
'
expires_at
'
=>
$
expiresAt
->
format
(
'
F j, Y
'
),
// timezone formatting can be passed separately
'
search_url
'
=>
route
(
'
show.ondemand.page
'
),
]);
return
$
email
;
}
Copy
Fix this →
Fix this →
3. squashNudgeRuns semantics change
3.
squashNudgeRuns
semantics change
app/Console/Commands/RemoveExpiredNudgesCommand.php:95
The condition changed from
whereNull('expires_at')
(only "never-expiring" nudges) to
where('expires_at', '>', now())
(all active nudges). Since nudges no longer have a "never expire" option this makes sense, but it's worth confirming: previously only nudges that had
expires_in = EXPIRE_NEVER
were squashed, now
all active nudges
are candidates. If that's intentional, a short comment explaining the rationale would help future readers.
4. SendNudgeExpirationWarningsCommand — missing Sentry capture
4.
SendNudgeExpirationWarningsCommand
— missing Sentry capture
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64
RemoveExpiredNudgesCommand
reports exceptions to Sentry;
SendNudgeExpirationWarningsCommand
only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding
Sentry::captureException($e)
in the
catch
block, consistent with the sibling command.
Fix this →
Fix this →
5. Minor — Command::SUCCESS constant
5. Minor —
Command::SUCCESS
constant
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:79
return
0
;
Copy
Should be
return Command::SUCCESS;
for readability and to match Laravel convention.
6. NudgeRepository — expires_at IS NULL edge case
6.
NudgeRepository
—
expires_at IS NULL
edge case
app/Component/Nudge/Repository/NudgeRepository.php:123
->
where
(
'
expires_at
'
,
'
>
'
,
now
())
Copy
This silently excludes any nudge with a
NULL
expires_at
(which should be zero after the migration runs, but worth noting). If the migration ever fails mid-run, affected nudges would stop triggering until the migration is re-run. Adding a note in the migration's docblock about this dependency would help with incident response.
7. Email template — link to specific section
7. Email template — link to specific section
resources/views/emails/postmark-templates/email/nudge-expiration-warning.email.mustache
The email instructs users to go to "Jiminny → On Demand → Saved Searches" but
search_url
points to the generic On Demand page. If a direct URL to the Saved Searches tab is available, using it would reduce friction for the user.
Summary
Summary
Severity
Issue
Medium
Migration does N+1 UPDATEs — use bulk queries
Medium
via()
side-effect in notification — breaks if queued
Low
squashNudgeRuns
now targets all active nudges — confirm intent
Low
Missing Sentry capture in warning command
Cosmetic
Use
Command::SUCCESS
constant
Informational
NULL expires_at
edge case in repository
UX
Email deep-link to Saved Searches tab
Severity
Medium
Medium
Low...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.16555852,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29837102,"top":0.20031923,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.23703113,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.07679521,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.31067154,"top":0.0,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.31067154,"top":0.0,"width":0.0029920214,"height":0.21468475},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"bounds":{"left":0.3159907,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"bounds":{"left":0.33061835,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"bounds":{"left":0.34391624,"top":0.008778931,"width":0.018949468,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"bounds":{"left":0.3459109,"top":0.014764565,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"bounds":{"left":0.3678524,"top":0.008778931,"width":0.017785905,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.3698471,"top":0.014764565,"width":0.008477394,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8166556,"top":0.008778931,"width":0.06565824,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"bounds":{"left":0.8289561,"top":0.014764565,"width":0.011801862,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"bounds":{"left":0.84208775,"top":0.016360734,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"bounds":{"left":0.84607714,"top":0.014764565,"width":0.021276595,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"bounds":{"left":0.8843085,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"bounds":{"left":0.89461434,"top":0.008778931,"width":0.008643617,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"bounds":{"left":0.9112367,"top":0.008778931,"width":0.01662234,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"bounds":{"left":0.9305186,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"bounds":{"left":0.9438165,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"bounds":{"left":0.95711434,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"bounds":{"left":0.97041225,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"bounds":{"left":0.9837101,"top":0.008778931,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"bounds":{"left":0.3103391,"top":0.0,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"bounds":{"left":0.3103391,"top":0.0,"width":0.0787899,"height":0.023144454},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"bounds":{"left":0.3159907,"top":0.04349561,"width":0.025099734,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"bounds":{"left":0.32679522,"top":0.04988029,"width":0.011469414,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"bounds":{"left":0.34375,"top":0.04349561,"width":0.054521278,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"bounds":{"left":0.3543883,"top":0.04988029,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.3863032,"top":0.057861134,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"bounds":{"left":0.38929522,"top":0.057861134,"width":0.004986702,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.39428192,"top":0.057861134,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"bounds":{"left":0.40093085,"top":0.04349561,"width":0.029089095,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"bounds":{"left":0.4119016,"top":0.04988029,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"bounds":{"left":0.43267953,"top":0.04349561,"width":0.03025266,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.44381648,"top":0.04988029,"width":0.015957447,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"bounds":{"left":0.46559176,"top":0.04349561,"width":0.022938829,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"bounds":{"left":0.47639626,"top":0.04988029,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (32)","depth":12,"bounds":{"left":0.49119017,"top":0.04349561,"width":0.070644945,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"bounds":{"left":0.50299203,"top":0.04988029,"width":0.04255319,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.5493683,"top":0.057861134,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"32","depth":14,"bounds":{"left":0.55236036,"top":0.057861134,"width":0.0056515955,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.55801195,"top":0.057861134,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"bounds":{"left":0.56449467,"top":0.04349561,"width":0.031083776,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"bounds":{"left":0.5756317,"top":0.04988029,"width":0.016788565,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.59823805,"top":0.04349561,"width":0.032081116,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.609375,"top":0.04988029,"width":0.017785905,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"bounds":{"left":0.32430187,"top":0.087789305,"width":0.0003324468,"height":0.016759777},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"bounds":{"left":0.32430187,"top":0.08938547,"width":0.039228722,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"bounds":{"left":0.32430187,"top":0.08938547,"width":0.2159242,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"bounds":{"left":0.54022604,"top":0.08938547,"width":0.04055851,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"bounds":{"left":0.54022604,"top":0.08938547,"width":0.04055851,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"bounds":{"left":0.58078456,"top":0.08938547,"width":0.08261303,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"bounds":{"left":0.6633976,"top":0.08938547,"width":0.05219415,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"bounds":{"left":0.6633976,"top":0.08938547,"width":0.05219415,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.7155917,"top":0.08938547,"width":0.0013297872,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"bounds":{"left":0.98603725,"top":0.0830008,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Review requested","depth":15,"bounds":{"left":0.46542552,"top":0.14604948,"width":0.0003324468,"height":0.016759777},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Review requested","depth":16,"bounds":{"left":0.46542552,"top":0.14764565,"width":0.039893616,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"bounds":{"left":0.46542552,"top":0.14764565,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"bounds":{"left":0.46542552,"top":0.14764565,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"requested your review on this pull request.","depth":15,"bounds":{"left":0.5036569,"top":0.14764565,"width":0.09158909,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Add your review","depth":14,"bounds":{"left":0.8174867,"top":0.14285715,"width":0.036901597,"height":0.022346368},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add your review","depth":16,"bounds":{"left":0.82047874,"top":0.14804469,"width":0.030917553,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JY-9712 | Nuges to expire after one year #11981 Edit title","depth":13,"bounds":{"left":0.453125,"top":0.18635276,"width":0.2293883,"height":0.031923383},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-9712 | Nuges to expire after one year","depth":14,"bounds":{"left":0.453125,"top":0.18715084,"width":0.18118352,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.6369681,"top":0.18715084,"width":0.0066489363,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11981","depth":15,"bounds":{"left":0.64361703,"top":0.18715084,"width":0.026928192,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"bounds":{"left":0.671875,"top":0.1895451,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unable to merge","depth":13,"bounds":{"left":0.7747673,"top":0.19273743,"width":0.053025264,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unable to merge","depth":15,"bounds":{"left":0.78706783,"top":0.19872306,"width":0.036402926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"bounds":{"left":0.82912236,"top":0.19273743,"width":0.02825798,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"bounds":{"left":0.8334442,"top":0.19872306,"width":0.011635638,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"bounds":{"left":0.4637633,"top":0.23064645,"width":0.011968086,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"bounds":{"left":0.48238033,"top":0.22745411,"width":0.03706782,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"bounds":{"left":0.48238033,"top":0.22905028,"width":0.03706782,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 14 commits into","depth":15,"bounds":{"left":0.52077794,"top":0.22905028,"width":0.068484046,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.5905917,"top":0.22705507,"width":0.018450798,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.59258646,"top":0.23024741,"width":0.014461436,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.61037236,"top":0.22905028,"width":0.009973404,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-9712-change-forever-nudges-to-1-year-expiration","depth":16,"bounds":{"left":0.62167555,"top":0.22705507,"width":0.12400266,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712-change-forever-nudges-to-1-year-expiration","depth":17,"bounds":{"left":0.6236702,"top":0.23024741,"width":0.1200133,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.74700797,"top":0.22466081,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 1276 additions & 1668 deletions","depth":14,"bounds":{"left":0.81349736,"top":0.28092578,"width":0.019946808,"height":0.11412609},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (11)","depth":16,"bounds":{"left":0.453125,"top":0.26296887,"width":0.05867686,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"bounds":{"left":0.46675533,"top":0.2725459,"width":0.028091755,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.50615025,"top":0.2725459,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":18,"bounds":{"left":0.5091423,"top":0.2725459,"width":0.0043218085,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.5134641,"top":0.2725459,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (14)","depth":16,"bounds":{"left":0.51180184,"top":0.26296887,"width":0.05036569,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"bounds":{"left":0.52543217,"top":0.2725459,"width":0.019115692,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.55651593,"top":0.2725459,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":18,"bounds":{"left":0.55950797,"top":0.2725459,"width":0.004986702,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.56449467,"top":0.2725459,"width":0.0018284575,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"bounds":{"left":0.5621675,"top":0.26296887,"width":0.04504654,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"bounds":{"left":0.57579786,"top":0.2725459,"width":0.015957447,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.6015625,"top":0.2725459,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"bounds":{"left":0.60455453,"top":0.2725459,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.60754657,"top":0.2725459,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (33)","depth":16,"bounds":{"left":0.6072141,"top":0.26296887,"width":0.061668884,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"bounds":{"left":0.6208444,"top":0.2725459,"width":0.029753989,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.6632314,"top":0.2725459,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":18,"bounds":{"left":0.6662234,"top":0.2725459,"width":0.0056515955,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.671875,"top":0.2725459,"width":0.0018284575,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation","depth":12,"bounds":{"left":0.453125,"top":0.3084597,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"bounds":{"left":0.453125,"top":0.31125298,"width":0.048204787,"height":0.023144454},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":12,"bounds":{"left":0.453125,"top":0.3084597,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"bounds":{"left":0.72672874,"top":0.30925778,"width":0.007978723,"height":0.02952913},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"nikolaybiaivanov commented last week","depth":14,"bounds":{"left":0.47739363,"top":0.30925778,"width":0.24135639,"height":0.02952913},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":16,"bounds":{"left":0.47739363,"top":0.31723863,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":17,"bounds":{"left":0.47739363,"top":0.31723863,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"bounds":{"left":0.515625,"top":0.31723863,"width":0.025598405,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":15,"bounds":{"left":0.5425532,"top":0.31564245,"width":0.020113032,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":17,"bounds":{"left":0.5425532,"top":0.31723863,"width":0.020113032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-9712","depth":16,"bounds":{"left":0.47739363,"top":0.35235435,"width":0.25731382,"height":0.017557861},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA:","depth":17,"bounds":{"left":0.47739363,"top":0.3527534,"width":0.015791224,"height":0.016759777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-9712","depth":17,"bounds":{"left":0.49318483,"top":0.3527534,"width":0.022606382,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-9712","depth":18,"bounds":{"left":0.49318483,"top":0.3527534,"width":0.022606382,"height":0.016759777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Deployment notes:","depth":16,"bounds":{"left":0.47739363,"top":0.38906625,"width":0.25731382,"height":0.01396648},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deployment notes:","depth":17,"bounds":{"left":0.47739363,"top":0.38906625,"width":0.042386968,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None","depth":18,"bounds":{"left":0.48537233,"top":0.41739824,"width":0.011303191,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":16,"bounds":{"left":0.47739363,"top":0.44533122,"width":0.008643617,"height":0.0207502},"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"@nikolaybiaivanov","depth":13,"bounds":{"left":0.453125,"top":0.5051876,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":14,"bounds":{"left":0.72672874,"top":0.5059856,"width":0.007978723,"height":0.02952913},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Author","depth":15,"bounds":{"left":0.7087766,"top":0.51556265,"width":0.012965426,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"nikolaybiaivanov commented last week","depth":13,"bounds":{"left":0.47739363,"top":0.5059856,"width":0.22240691,"height":0.02952913},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":15,"bounds":{"left":0.47739363,"top":0.5139665,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":16,"bounds":{"left":0.47739363,"top":0.5139665,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":14,"bounds":{"left":0.515625,"top":0.5139665,"width":0.025598405,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":14,"bounds":{"left":0.5425532,"top":0.5123703,"width":0.020113032,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":16,"bounds":{"left":0.5425532,"top":0.5139665,"width":0.020113032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@claude","depth":17,"bounds":{"left":0.47739363,"top":0.5506784,"width":0.019115692,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@claude","depth":18,"bounds":{"left":0.47739363,"top":0.5506784,"width":0.019115692,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":15,"bounds":{"left":0.47739363,"top":0.5786113,"width":0.008643617,"height":0.0207502},"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"react with eyes","depth":14,"bounds":{"left":0.48736703,"top":0.5786113,"width":0.013796543,"height":0.0207502},"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"👀","depth":16,"bounds":{"left":0.4895279,"top":0.5837989,"width":0.004155585,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"bounds":{"left":0.49634308,"top":0.5837989,"width":0.0018284575,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@claude","depth":13,"bounds":{"left":0.453125,"top":0.63846767,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":14,"bounds":{"left":0.72672874,"top":0.6392658,"width":0.007978723,"height":0.02952913},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"claude Bot commented last week •","depth":13,"bounds":{"left":0.47739363,"top":0.6392658,"width":0.24135639,"height":0.029928172},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"claude","depth":15,"bounds":{"left":0.47739363,"top":0.6472466,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"claude","depth":16,"bounds":{"left":0.47739363,"top":0.6472466,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bot","depth":16,"bounds":{"left":0.49584442,"top":0.64884275,"width":0.0066489363,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":14,"bounds":{"left":0.50615025,"top":0.64764565,"width":0.02543218,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"last week","depth":14,"bounds":{"left":0.53291225,"top":0.6460495,"width":0.020113032,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"last week","depth":16,"bounds":{"left":0.53291225,"top":0.64764565,"width":0.020113032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":16,"bounds":{"left":0.554355,"top":0.64764565,"width":0.0021609042,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"edited","depth":16,"bounds":{"left":0.5578458,"top":0.6460495,"width":0.020113032,"height":0.016759777},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"edited","depth":18,"bounds":{"left":0.5578458,"top":0.64764565,"width":0.014793883,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude finished","depth":18,"bounds":{"left":0.47739363,"top":0.6843575,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@nikolaybiaivanov","depth":18,"bounds":{"left":0.5134641,"top":0.6843575,"width":0.04138963,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@nikolaybiaivanov","depth":19,"bounds":{"left":0.5134641,"top":0.6843575,"width":0.04138963,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'s task in 2m 9s","depth":18,"bounds":{"left":0.55485374,"top":0.6843575,"width":0.03523936,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"——","depth":17,"bounds":{"left":0.5900931,"top":0.6843575,"width":0.010638298,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View job","depth":17,"bounds":{"left":0.6007314,"top":0.6843575,"width":0.018284574,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View job","depth":18,"bounds":{"left":0.6007314,"top":0.6843575,"width":0.018284574,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Code Review","depth":16,"bounds":{"left":0.47739363,"top":0.7406225,"width":0.25731382,"height":0.017557861},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Code Review","depth":17,"bounds":{"left":0.47739363,"top":0.7410216,"width":0.03523936,"height":0.016759777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.7753392,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gather context and read changed files","depth":18,"bounds":{"left":0.48537233,"top":0.7741421,"width":0.08361037,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.7952913,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeFactory.php changes","depth":18,"bounds":{"left":0.48537233,"top":0.79409415,"width":0.076961435,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.8152434,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeRepository.php changes","depth":18,"bounds":{"left":0.48537233,"top":0.81404626,"width":0.083942816,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.8355946,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review RemoveExpiredNudgesCommand.php changes","depth":18,"bounds":{"left":0.48537233,"top":0.8339984,"width":0.11884973,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.8555467,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review SendNudgeExpirationWarningsCommand.php (new)","depth":18,"bounds":{"left":0.48537233,"top":0.85434955,"width":0.12948804,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.87549883,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeController.php changes","depth":18,"bounds":{"left":0.48537233,"top":0.8743017,"width":0.08211436,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.8954509,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review Nudge.php model changes","depth":18,"bounds":{"left":0.48537233,"top":0.8942538,"width":0.07579787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.915403,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review NudgeExpirationWarningNotification.php (new)","depth":18,"bounds":{"left":0.48537233,"top":0.9142059,"width":0.11884973,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.9353551,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review migration file (new)","depth":18,"bounds":{"left":0.48537233,"top":0.934158,"width":0.059507977,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.95530725,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review email templates (new)","depth":18,"bounds":{"left":0.48537233,"top":0.95411015,"width":0.0653258,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.97525936,"width":0.004654255,"height":0.011173184},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review Kernel.php changes","depth":18,"bounds":{"left":0.48537233,"top":0.97406226,"width":0.06050532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Completed task","depth":18,"bounds":{"left":0.47972074,"top":0.99561054,"width":0.004654255,"height":0.004389465},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Post final review","depth":18,"bounds":{"left":0.48537233,"top":0.9940144,"width":0.036402926,"height":0.0059856176},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overall this is a well-structured refactor. The removal of the legacy","depth":17,"bounds":{"left":0.47739363,"top":1.0,"width":0.14444813,"height":-0.053870678},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_in","depth":18,"bounds":{"left":0.62333775,"top":1.0,"width":0.023936171,"height":-0.055865884},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"integer enum in favour of a real datetime","depth":17,"bounds":{"left":0.47739363,"top":1.0,"width":0.23969415,"height":-0.053870678},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":18,"bounds":{"left":0.49916887,"top":1.0,"width":0.023769947,"height":-0.072625756},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:","depth":17,"bounds":{"left":0.47739363,"top":1.0,"width":0.24517952,"height":-0.07063043},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Migration: per-row UPDATE is slow at scale","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Migration: per-row UPDATE is slow at scale","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The migration issues one","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Nudges older than 1 year → expire in 8 days","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SET","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_ADD(NOW(), INTERVAL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DAY)","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WHERE","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at IS","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AND","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"created_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"<","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_SUB(NOW(), INTERVAL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR);","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Newer nudges → expire 1 year after creation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UPDATE","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SET","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_ADD(created_at, INTERVAL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR)","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"WHERE","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at IS","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AND","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"created_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":">=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE_SUB(NOW(), INTERVAL","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"YEAR);","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"The","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"endOfDay()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereIn","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"on IDs per chunk rather than one query per row.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix this →","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. NudgeExpirationWarningNotification — side-effect in via()","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NudgeExpirationWarningNotification","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— side-effect in","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Notifications/NudgeExpirationWarningNotification.php:15–29","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$formattedExpiresAt","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is set in","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and consumed in","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". This creates an implicit ordering dependency. Laravel does call","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark()","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(or a private helper called from there) to make it self-contained:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"function","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"toPostmark","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"():","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EmailWithTemplate","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"new","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EmailWithTemplate","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge-expiration-warning","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getActivitySearch","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"();","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expiresAt","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"this","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getExpiresAt","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"();","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setData","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"([","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudge_name","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getName","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(),","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expiresAt","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"format","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"F j, Y","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"),","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// timezone formatting can be passed separately","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search_url","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=>","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"route","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"show.ondemand.page","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"),\n ]);","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"email","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";\n}","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Fix this →","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. squashNudgeRuns semantics change","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"squashNudgeRuns","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"semantics change","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Console/Commands/RemoveExpiredNudgesCommand.php:95","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The condition changed from","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNull('expires_at')","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(only \"never-expiring\" nudges) to","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"where('expires_at', '>', now())","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(all active nudges). Since nudges no longer have a \"never expire\" option this makes sense, but it's worth confirming: previously only nudges that had","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_in = EXPIRE_NEVER","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"were squashed, now","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"all active nudges","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"are candidates. If that's intentional, a short comment explaining the rationale would help future readers.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"4. SendNudgeExpirationWarningsCommand — missing Sentry capture","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SendNudgeExpirationWarningsCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— missing Sentry capture","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RemoveExpiredNudgesCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reports exceptions to Sentry;","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SendNudgeExpirationWarningsCommand","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sentry::captureException($e)","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"catch","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"block, consistent with the sibling command.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fix this →","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fix this →","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"5. Minor — Command::SUCCESS constant","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5. Minor —","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Command::SUCCESS","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Console/Commands/SendNudgeExpirationWarningsCommand.php:79","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":";","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Should be","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return Command::SUCCESS;","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for readability and to match Laravel convention.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"6. NudgeRepository — expires_at IS NULL edge case","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NudgeRepository","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at IS NULL","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"edge case","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/Nudge/Repository/NudgeRepository.php:123","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"->","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"where","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":">","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"now","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"())","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"This silently excludes any nudge with a","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expires_at","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(which should be zero after the migration runs, but worth noting). If the migration ever fails mid-run, affected nudges would stop triggering until the migration is re-run. Adding a note in the migration's docblock about this dependency would help with incident response.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"7. Email template — link to specific section","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7. Email template — link to specific section","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"resources/views/emails/postmark-templates/email/nudge-expiration-warning.email.mustache","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The email instructs users to go to \"Jiminny → On Demand → Saved Searches\" but","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"search_url","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"points to the generic On Demand page. If a direct URL to the Saved Searches tab is available, using it would reduce friction for the user.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Summary","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Summary","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Severity","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Issue","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Medium","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Migration does N+1 UPDATEs — use bulk queries","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Medium","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via()","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"side-effect in notification — breaks if queued","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Low","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"squashNudgeRuns","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"now targets all active nudges — confirm intent","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Low","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Missing Sentry capture in warning command","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cosmetic","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Use","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Command::SUCCESS","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Informational","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL expires_at","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"edge case in repository","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UX","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Email deep-link to Saved Searches tab","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Severity","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Medium","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Medium","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Low","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7025850059065958842
|
6658990905085020809
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
JY-9712 | Nuges to expire after one year by nikolaybiaivanov · Pull Request #11981 · jiminny/app
Close tab
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (32)
Security and quality
(
32
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Review requested
Review requested
nikolaybiaivanov
nikolaybiaivanov
requested your review on this pull request.
Add your review
Add your review
JY-9712 | Nuges to expire after one year #11981 Edit title
JY-9712 | Nuges to expire after one year
#
11981
Edit title
Unable to merge
Unable to merge
Code
Code
Open
nikolaybiaivanov
nikolaybiaivanov
wants to merge 14 commits into
master
master
from
JY-9712-change-forever-nudges-to-1-year-expiration
JY-9712-change-forever-nudges-to-1-year-expiration
Copy head branch name to clipboard
Lines changed: 1276 additions & 1668 deletions
Conversation (11)
Conversation
(
11
)
Commits (14)
Commits
(
14
)
Checks (3)
Checks
(
3
)
Files changed (33)
Files changed
(
33
)
Conversation
Conversation
@nikolaybiaivanov
Show options
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
JIRA: JY-9712
JIRA:
JY-9712
JY-9712
Deployment notes:
Deployment notes:
None
Add or remove reactions
@nikolaybiaivanov
Show options
Author
nikolaybiaivanov commented last week
nikolaybiaivanov
nikolaybiaivanov
commented
last week
last week
@claude
@claude
Add or remove reactions
react with eyes
👀
1
@claude
Show options
claude Bot commented last week •
claude
claude
Bot
commented
last week
last week
•
edited
edited
Claude finished
@nikolaybiaivanov
@nikolaybiaivanov
's task in 2m 9s
——
View job
View job
Code Review
Code Review
Completed task
Gather context and read changed files
Completed task
Review NudgeFactory.php changes
Completed task
Review NudgeRepository.php changes
Completed task
Review RemoveExpiredNudgesCommand.php changes
Completed task
Review SendNudgeExpirationWarningsCommand.php (new)
Completed task
Review NudgeController.php changes
Completed task
Review Nudge.php model changes
Completed task
Review NudgeExpirationWarningNotification.php (new)
Completed task
Review migration file (new)
Completed task
Review email templates (new)
Completed task
Review Kernel.php changes
Completed task
Post final review
Overall this is a well-structured refactor. The removal of the legacy
expires_in
integer enum in favour of a real datetime
expires_at
, the migration for existing data, and the warning-email pipeline all fit together cleanly. A few things worth looking at:
1. Migration: per-row UPDATE is slow at scale
1. Migration: per-row UPDATE is slow at scale
database/migrations/2026_04_16_121204_migrate_existing_nudges_expiration_data.php
The migration issues one
UPDATE
per nudge inside a chunk loop. For large tables this will be very slow. You can replace it with two bulk updates and drop the PHP loop entirely:
--
Nudges older than 1 year → expire in 8 days
UPDATE
nudges
SET
expires_at
=
DATE_ADD(NOW(), INTERVAL
8
DAY)
WHERE
expires_at IS
NULL
AND
created_at
<
DATE_SUB(NOW(), INTERVAL
1
YEAR);
--
Newer nudges → expire 1 year after creation
UPDATE
nudges
SET
expires_at
=
DATE_ADD(created_at, INTERVAL
1
YEAR)
WHERE
expires_at IS
NULL
AND
created_at
>=
DATE_SUB(NOW(), INTERVAL
1
YEAR);
Copy
The
endOfDay()
adjustment is a nice touch that should be preserved if you keep the chunk approach; raw SQL would lose that. But even a chunk-based approach can batch the updates with a single
whereIn
on IDs per chunk rather than one query per row.
Fix this →
Fix this →
2. NudgeExpirationWarningNotification — side-effect in via()
2.
NudgeExpirationWarningNotification
— side-effect in
via()
app/Notifications/NudgeExpirationWarningNotification.php:15–29
$formattedExpiresAt
is set in
via()
and consumed in
toPostmark()
. This creates an implicit ordering dependency. Laravel does call
via()
first, but if this notification is ever queued or serialised the state won't survive. Move the formatting logic into
toPostmark()
(or a private helper called from there) to make it self-contained:
public
function
toPostmark
():
EmailWithTemplate
{
$
email
=
new
EmailWithTemplate
(
'
nudge-expiration-warning
'
);
$
search
=
$
this
->
nudge
->
getActivitySearch
();
$
expiresAt
=
$
this
->
nudge
->
getExpiresAt
();
$
email
->
setData
([
'
nudge_name
'
=>
$
search
->
getName
(),
'
expires_at
'
=>
$
expiresAt
->
format
(
'
F j, Y
'
),
// timezone formatting can be passed separately
'
search_url
'
=>
route
(
'
show.ondemand.page
'
),
]);
return
$
email
;
}
Copy
Fix this →
Fix this →
3. squashNudgeRuns semantics change
3.
squashNudgeRuns
semantics change
app/Console/Commands/RemoveExpiredNudgesCommand.php:95
The condition changed from
whereNull('expires_at')
(only "never-expiring" nudges) to
where('expires_at', '>', now())
(all active nudges). Since nudges no longer have a "never expire" option this makes sense, but it's worth confirming: previously only nudges that had
expires_in = EXPIRE_NEVER
were squashed, now
all active nudges
are candidates. If that's intentional, a short comment explaining the rationale would help future readers.
4. SendNudgeExpirationWarningsCommand — missing Sentry capture
4.
SendNudgeExpirationWarningsCommand
— missing Sentry capture
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:56–64
RemoveExpiredNudgesCommand
reports exceptions to Sentry;
SendNudgeExpirationWarningsCommand
only logs them. If sending a warning fails silently in production you won't get an alert. Consider adding
Sentry::captureException($e)
in the
catch
block, consistent with the sibling command.
Fix this →
Fix this →
5. Minor — Command::SUCCESS constant
5. Minor —
Command::SUCCESS
constant
app/Console/Commands/SendNudgeExpirationWarningsCommand.php:79
return
0
;
Copy
Should be
return Command::SUCCESS;
for readability and to match Laravel convention.
6. NudgeRepository — expires_at IS NULL edge case
6.
NudgeRepository
—
expires_at IS NULL
edge case
app/Component/Nudge/Repository/NudgeRepository.php:123
->
where
(
'
expires_at
'
,
'
>
'
,
now
())
Copy
This silently excludes any nudge with a
NULL
expires_at
(which should be zero after the migration runs, but worth noting). If the migration ever fails mid-run, affected nudges would stop triggering until the migration is re-run. Adding a note in the migration's docblock about this dependency would help with incident response.
7. Email template — link to specific section
7. Email template — link to specific section
resources/views/emails/postmark-templates/email/nudge-expiration-warning.email.mustache
The email instructs users to go to "Jiminny → On Demand → Saved Searches" but
search_url
points to the generic On Demand page. If a direct URL to the Saved Searches tab is available, using it would reduce friction for the user.
Summary
Summary
Severity
Issue
Medium
Migration does N+1 UPDATEs — use bulk queries
Medium
via()
side-effect in notification — breaks if queued
Low
squashNudgeRuns
now targets all active nudges — confirm intent
Low
Missing Sentry capture in warning command
Cosmetic
Use
Command::SUCCESS
constant
Informational
NULL expires_at
edge case in repository
UX
Email deep-link to Saved Searches tab
Severity
Medium
Medium
Low...
|
NULL
|
|
76507
|
NULL
|
0
|
2026-04-24T08:04:02.676930+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017842676_m1.jpg...
|
Firefox
|
Inbox - kovaliklukas@gmail.com - Gmail — Personal
|
True
|
mail.google.com/mail/u/0/#inbox
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(67) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Mute tab
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
None selected
Skip to content
Skip to content
Using Gmail with screen readers
Using Gmail with screen readers
Main menu
Gmail
Search
Search
Search mail
Advanced search options
Search mail
Support
Settings
Ask Gemini
Google apps
Google Account: Lukáš Koválik ([EMAIL]), Storage usage alert
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 7 unread
Drafts
7
Purchases has menu
Purchases
Social 5165 unread has menu
Social
5,165
Updates 8687 unread has menu
Updates
8,687
Forums 6048 unread has menu
Forums
6,048
Promotions 38629 unread has menu
Promotions
38,629
More labels
More
Labels
Labels
Create new label
Labels
Labels
[Imap]/Nevyžiadaná pošta has menu
[Imap]/Nevyžiadaná pošta
arch has menu
arch
Deleted Items has menu
Deleted Items
Fibank 1229 unread has menu
Fibank
1,229
FL 6 unread has menu
FL
6
Hardware & Software has menu
Hardware & Software
HOSTING 5 unread has menu
HOSTING
5
Infected Items has menu
Infected Items
jiminny-github 7421 unread has menu
jiminny-github
7,421
Junk E-mail 219 unread has menu
Junk E-mail
219
Kontakty has menu
Kontakty
Sent Items has menu
Sent Items
WORK 848 unread has menu
WORK
848
z centra 1274 unread has menu
z centra
1,274
More labels
More
Select
Refresh
More email options
Show more messages
1
–
50
of
21,145
Newer
Older
Toggle split pane mode
Input tools on/off (Ctrl-Shift-K)
Select input tool
Conversations
Conversations
Primary
Primary
Promotions, 50 new messages,
50 new
Promotions
Social, 25 new messages,
25 new
Social
Updates
Updates
Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.
Not starred
Important because it matched one of your importance filters.
Notion Team
Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
Get a first look at our developer tools
-
Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
10:45
CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.
Not starred
Not important
CircleCI Builds
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification
-
app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
10:40
imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.
Not starred
Not important
imot.bg
Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
Известяване за промяна в цена от imot.bg
-
Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
09:03
Medium Weekly Digest, Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained, 08:20, Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,.
Not starred
Important according to Google magic.
Medium Weekly Digest
Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained - Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,
Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained
-
Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,
08:20
Proton, You have 1 new message(s) in your Proton Mail account k[PASSWORD_DOTS], 01:42, Please log in at https://mail.proton.me to check them. [Proton](https://proton.me/) You have 1 new message(s) Hello, You have 1 new message(s) in your inbox and custom folders. Please log in at https:/.
Not starred
Important according to Google magic....
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"5 Signs You Have Successfully Hurt a Narcissist; - kovaliklukas@gmail.com - Gmail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"(67) Inbox | kovaliklukas@proton.me | Proton Mail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Today's Deals","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today's Deals","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"architecture - screenpipe docs","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"architecture - screenpipe docs","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Platform","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Platform","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"rescue time detailed overview - Google Search","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"rescue time detailed overview - Google Search","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Mute tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"None selected","depth":8,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using Gmail with screen readers","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Using Gmail with screen readers","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Main menu","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"Gmail","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Search","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search mail","depth":18,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Advanced search options","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search mail","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Support","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Settings","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Ask Gemini","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Google apps","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com), Storage usage alert","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compose","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Starred","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Starred","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Snoozed","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Snoozed","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Important","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Important","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sent","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Drafts 7 unread","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Drafts","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Purchases has menu","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Purchases","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Social 5165 unread has menu","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Social","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5,165","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Updates 8687 unread has menu","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Updates","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8,687","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums 6048 unread has menu","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6,048","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Promotions 38629 unread has menu","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Promotions","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38,629","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Labels","depth":11,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create new label","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[Imap]/Nevyžiadaná pošta has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[Imap]/Nevyžiadaná pošta","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"arch has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"arch","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deleted Items has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deleted Items","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fibank 1229 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fibank","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,229","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"FL 6 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"FL","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hardware & Software has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hardware & Software","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HOSTING 5 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HOSTING","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Infected Items has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Infected Items","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"jiminny-github 7421 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny-github","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7,421","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Junk E-mail 219 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Junk E-mail","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"219","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kontakty has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontakty","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent Items has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sent Items","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"WORK 848 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"WORK","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"848","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"z centra 1274 unread has menu","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"z centra","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,274","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Select","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Refresh","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More email options","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show more messages","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"–","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"50","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"of","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21,145","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Newer","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Older","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle split pane mode","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Input tools on/off (Ctrl-Shift-K)","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Select input tool","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversations","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversations","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Primary","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Primary","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Promotions, 50 new messages,","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"50 new","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Promotions","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Social, 25 new messages,","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25 new","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Social","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updates","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Important because it matched one of your importance filters.","depth":18,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notion Team","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Get a first look at our developer tools","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:45","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Not important","depth":18,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CircleCI Builds","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:40","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Not important","depth":18,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"imot.bg","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Известяване за промяна в цена от imot.bg","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"09:03","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Medium Weekly Digest, Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained, 08:20, Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,.","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Important according to Google magic.","depth":18,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Medium Weekly Digest","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained - Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,","depth":18,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08:20","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Proton, You have 1 new message(s) in your Proton Mail account k***********, 01:42, Please log in at https://mail.proton.me to check them. [Proton](https://proton.me/) You have 1 new message(s) Hello, You have 1 new message(s) in your inbox and custom folders. Please log in at https:/.","depth":18,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Important according to Google magic.","depth":18,"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-6480900576553545285
|
-9171883464535172399
|
idle
|
accessibility
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(67) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Mute tab
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
None selected
Skip to content
Skip to content
Using Gmail with screen readers
Using Gmail with screen readers
Main menu
Gmail
Search
Search
Search mail
Advanced search options
Search mail
Support
Settings
Ask Gemini
Google apps
Google Account: Lukáš Koválik ([EMAIL]), Storage usage alert
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 7 unread
Drafts
7
Purchases has menu
Purchases
Social 5165 unread has menu
Social
5,165
Updates 8687 unread has menu
Updates
8,687
Forums 6048 unread has menu
Forums
6,048
Promotions 38629 unread has menu
Promotions
38,629
More labels
More
Labels
Labels
Create new label
Labels
Labels
[Imap]/Nevyžiadaná pošta has menu
[Imap]/Nevyžiadaná pošta
arch has menu
arch
Deleted Items has menu
Deleted Items
Fibank 1229 unread has menu
Fibank
1,229
FL 6 unread has menu
FL
6
Hardware & Software has menu
Hardware & Software
HOSTING 5 unread has menu
HOSTING
5
Infected Items has menu
Infected Items
jiminny-github 7421 unread has menu
jiminny-github
7,421
Junk E-mail 219 unread has menu
Junk E-mail
219
Kontakty has menu
Kontakty
Sent Items has menu
Sent Items
WORK 848 unread has menu
WORK
848
z centra 1274 unread has menu
z centra
1,274
More labels
More
Select
Refresh
More email options
Show more messages
1
–
50
of
21,145
Newer
Older
Toggle split pane mode
Input tools on/off (Ctrl-Shift-K)
Select input tool
Conversations
Conversations
Primary
Primary
Promotions, 50 new messages,
50 new
Promotions
Social, 25 new messages,
25 new
Social
Updates
Updates
Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.
Not starred
Important because it matched one of your importance filters.
Notion Team
Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
Get a first look at our developer tools
-
Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
10:45
CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.
Not starred
Not important
CircleCI Builds
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification
-
app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
10:40
imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.
Not starred
Not important
imot.bg
Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
Известяване за промяна в цена от imot.bg
-
Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
09:03
Medium Weekly Digest, Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained, 08:20, Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,.
Not starred
Important according to Google magic.
Medium Weekly Digest
Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained - Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,
Docker, Kubernetes, and Helm — Intuitively and Exhaustively Explained | Daniel Warfield in Intuitively and Exhaustively Explained
-
Lukáš Koválik Stories for Lukáš Koválik @kovaliklukas·Become a member Medium weekly digest Today's highlights Daniel Warfield Daniel WarfieldinIntuitively and Exhaustively Explained Docker,
08:20
Proton, You have 1 new message(s) in your Proton Mail account k[PASSWORD_DOTS], 01:42, Please log in at https://mail.proton.me to check them. [Proton](https://proton.me/) You have 1 new message(s) Hello, You have 1 new message(s) in your inbox and custom folders. Please log in at https:/.
Not starred
Important according to Google magic....
|
NULL
|
|
76508
|
NULL
|
0
|
2026-04-24T08:04:02.935591+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777017842935_m2.jpg...
|
Firefox
|
Inbox - kovaliklukas@gmail.com - Gmail — Personal
|
True
|
mail.google.com/mail/u/0/#inbox
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(67) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Mute tab
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
None selected
Skip to content
Skip to content
Using Gmail with screen readers
Using Gmail with screen readers
Main menu
Gmail
Search
Search
Search mail
Advanced search options
Search mail
Support
Settings
Ask Gemini
Google apps
Google Account: Lukáš Koválik ([EMAIL]), Storage usage alert
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 7 unread
Drafts
7
Purchases has menu
Purchases
Social 5165 unread has menu
Social
5,165
Updates 8687 unread has menu
Updates
8,687
Forums 6048 unread has menu
Forums
6,048
Promotions 38629 unread has menu
Promotions
38,629
More labels
More
Labels
Labels
Create new label
Labels
Labels
[Imap]/Nevyžiadaná pošta has menu
[Imap]/Nevyžiadaná pošta
arch has menu
arch
Deleted Items has menu
Deleted Items
Fibank 1229 unread has menu
Fibank
1,229
FL 6 unread has menu
FL
6
Hardware & Software has menu
Hardware & Software
HOSTING 5 unread has menu
HOSTING
5
Infected Items has menu
Infected Items
jiminny-github 7421 unread has menu
jiminny-github
7,421
Junk E-mail 219 unread has menu
Junk E-mail
219
Kontakty has menu
Kontakty
Sent Items has menu
Sent Items
WORK 848 unread has menu
WORK
848
z centra 1274 unread has menu
z centra
1,274
More labels
More
Select
Refresh
More email options
Show more messages
1
–
50
of
21,145
Newer
Older
Toggle split pane mode
Input tools on/off (Ctrl-Shift-K)
Select input tool
Conversations
Conversations
Primary
Primary
Promotions, 50 new messages,
50 new
Promotions
Social, 25 new messages,
25 new
Social
Updates
Updates
Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.
Not starred
Important because it matched one of your importance filters.
Notion Team
Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
Get a first look at our developer tools
-
Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
10:45
CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.
Not starred
Not important
CircleCI Builds
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification
-
app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
10:40
imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.
Not starred
Not important
imot.bg
Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
Известяване за промяна в цена от imot.bg
-
Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.03673537,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"5 Signs You Have Successfully Hurt a Narcissist; - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.26961437,"top":0.0518755,"width":0.03656915,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"(67) Inbox | kovaliklukas@proton.me | Proton Mail","depth":4,"bounds":{"left":0.30618352,"top":0.0518755,"width":0.03673537,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.26263297,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Today's Deals","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Today's Deals","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.024102394,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"architecture - screenpipe docs","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"architecture - screenpipe docs","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.053523935,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.20844415,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.2443484,"top":0.23703113,"width":0.037898935,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.2443484,"top":0.2697526,"width":0.040724736,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.03756649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Platform","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Platform","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.027925532,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"rescue time detailed overview - Google Search","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"rescue time detailed overview - Google Search","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.08128324,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":4,"bounds":{"left":0.23105054,"top":0.38946527,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hey @louis030195 Ill check during my - screenpipe.com","depth":5,"bounds":{"left":0.2443484,"top":0.40063846,"width":0.09790558,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":4,"bounds":{"left":0.23105054,"top":0.42218676,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub","depth":5,"bounds":{"left":0.2443484,"top":0.43335995,"width":0.22556517,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":4,"bounds":{"left":0.23105054,"top":0.45490822,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gong Pricing in 2026: Costs, Plans & Is It Worth It?","depth":5,"bounds":{"left":0.2443484,"top":0.4660814,"width":0.08826463,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube","depth":4,"bounds":{"left":0.23105054,"top":0.48762968,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Mute tab","depth":5,"bounds":{"left":0.24251994,"top":0.49481246,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube","depth":5,"bounds":{"left":0.25116357,"top":0.49880287,"width":0.14394946,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.23105054,"top":0.5203512,"width":0.113696806,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.2443484,"top":0.53152436,"width":0.06898271,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.3324468,"top":0.5275339,"width":0.007978723,"height":0.01915403},"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.23387633,"top":0.5546688,"width":0.108211435,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"None selected","depth":8,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using Gmail with screen readers","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Using Gmail with screen readers","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Main menu","depth":11,"bounds":{"left":0.3487367,"top":0.058260176,"width":0.015957447,"height":0.03830806},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"Gmail","depth":12,"bounds":{"left":0.36602393,"top":0.061452515,"width":0.036236703,"height":0.035115723},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Search","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search mail","depth":18,"bounds":{"left":0.4481383,"top":0.06943336,"width":0.18916224,"height":0.016360734},"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Advanced search options","depth":12,"bounds":{"left":0.6505984,"top":0.058260176,"width":0.01861702,"height":0.03671189},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search mail","depth":12,"bounds":{"left":0.42985374,"top":0.058260176,"width":0.01861702,"height":0.03671189},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Support","depth":13,"bounds":{"left":0.92353725,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9381649,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Ask Gemini","depth":13,"bounds":{"left":0.95212764,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Google apps","depth":14,"bounds":{"left":0.96609044,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com), Storage usage alert","depth":14,"bounds":{"left":0.98204786,"top":0.061452515,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compose","depth":9,"bounds":{"left":0.34740692,"top":0.10933759,"width":0.04737367,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox","depth":16,"bounds":{"left":0.36602393,"top":0.15003991,"width":0.012466756,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox","depth":17,"bounds":{"left":0.36602393,"top":0.15003991,"width":0.012466756,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Starred","depth":17,"bounds":{"left":0.36602393,"top":0.16919394,"width":0.015625,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Starred","depth":18,"bounds":{"left":0.36602393,"top":0.16919394,"width":0.015625,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Snoozed","depth":17,"bounds":{"left":0.36602393,"top":0.18834797,"width":0.018284574,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Snoozed","depth":18,"bounds":{"left":0.36602393,"top":0.18834797,"width":0.018284574,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Important","depth":17,"bounds":{"left":0.36602393,"top":0.207502,"width":0.020777926,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Important","depth":18,"bounds":{"left":0.36602393,"top":0.207502,"width":0.020777926,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent","depth":17,"bounds":{"left":0.36602393,"top":0.22665602,"width":0.009640957,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sent","depth":18,"bounds":{"left":0.36602393,"top":0.22665602,"width":0.009640957,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Drafts 7 unread","depth":17,"bounds":{"left":0.36602393,"top":0.24581006,"width":0.013796543,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Drafts","depth":18,"bounds":{"left":0.36602393,"top":0.24581006,"width":0.013796543,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":17,"bounds":{"left":0.41988033,"top":0.24700718,"width":0.0019946808,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Purchases has menu","depth":16,"bounds":{"left":0.36602393,"top":0.26496407,"width":0.021941489,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Purchases","depth":17,"bounds":{"left":0.36602393,"top":0.26496407,"width":0.021941489,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Social 5165 unread has menu","depth":16,"bounds":{"left":0.36602393,"top":0.28411812,"width":0.013796543,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Social","depth":17,"bounds":{"left":0.36602393,"top":0.28411812,"width":0.013796543,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5,165","depth":16,"bounds":{"left":0.41273272,"top":0.28531525,"width":0.009142287,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Updates 8687 unread has menu","depth":16,"bounds":{"left":0.36602393,"top":0.30327216,"width":0.018949468,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Updates","depth":17,"bounds":{"left":0.36602393,"top":0.30327216,"width":0.018949468,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8,687","depth":16,"bounds":{"left":0.41223404,"top":0.3044693,"width":0.009640957,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums 6048 unread has menu","depth":16,"bounds":{"left":0.36602393,"top":0.32242617,"width":0.016788565,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":17,"bounds":{"left":0.36602393,"top":0.32242617,"width":0.016788565,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6,048","depth":16,"bounds":{"left":0.4114029,"top":0.3236233,"width":0.010472074,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Promotions 38629 unread has menu","depth":16,"bounds":{"left":0.36602393,"top":0.3415802,"width":0.025930852,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Promotions","depth":17,"bounds":{"left":0.36602393,"top":0.3415802,"width":0.025930852,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38,629","depth":16,"bounds":{"left":0.40990692,"top":0.34277734,"width":0.011968086,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"bounds":{"left":0.34474733,"top":0.35834,"width":0.07978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.36602393,"top":0.36073422,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Labels","depth":11,"bounds":{"left":0.35339096,"top":0.39984038,"width":0.061835106,"height":0.016360734},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":12,"bounds":{"left":0.35339096,"top":0.39984038,"width":0.016456118,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create new label","depth":11,"bounds":{"left":0.41522607,"top":0.40023944,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[Imap]/Nevyžiadaná pošta has menu","depth":17,"bounds":{"left":0.36602393,"top":0.42817238,"width":0.055352394,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[Imap]/Nevyžiadaná pošta","depth":18,"bounds":{"left":0.36602393,"top":0.42817238,"width":0.055352394,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"arch has menu","depth":17,"bounds":{"left":0.36602393,"top":0.44732642,"width":0.009474734,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"arch","depth":18,"bounds":{"left":0.36602393,"top":0.44732642,"width":0.009474734,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deleted Items has menu","depth":17,"bounds":{"left":0.36602393,"top":0.46648043,"width":0.029089095,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deleted Items","depth":18,"bounds":{"left":0.36602393,"top":0.46648043,"width":0.029089095,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fibank 1229 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.48563448,"width":0.01512633,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fibank","depth":18,"bounds":{"left":0.36602393,"top":0.48563448,"width":0.01512633,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,229","depth":17,"bounds":{"left":0.41273272,"top":0.4868316,"width":0.009142287,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"FL 6 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.5047885,"width":0.005319149,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"FL","depth":18,"bounds":{"left":0.36602393,"top":0.5047885,"width":0.005319149,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":17,"bounds":{"left":0.4195479,"top":0.5059856,"width":0.0023271276,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hardware & Software has menu","depth":17,"bounds":{"left":0.36602393,"top":0.52394253,"width":0.044714097,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Hardware & Software","depth":18,"bounds":{"left":0.36602393,"top":0.52394253,"width":0.044714097,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HOSTING 5 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.54309654,"width":0.02144282,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HOSTING","depth":18,"bounds":{"left":0.36602393,"top":0.54309654,"width":0.02144282,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":17,"bounds":{"left":0.4197141,"top":0.5442937,"width":0.0021609042,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Infected Items has menu","depth":17,"bounds":{"left":0.36602393,"top":0.5622506,"width":0.030086435,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Infected Items","depth":18,"bounds":{"left":0.36602393,"top":0.5622506,"width":0.030086435,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"jiminny-github 7421 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.5814046,"width":0.03324468,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny-github","depth":18,"bounds":{"left":0.36602393,"top":0.5814046,"width":0.03324468,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7,421","depth":17,"bounds":{"left":0.41323137,"top":0.5826017,"width":0.008643617,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Junk E-mail 219 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.60055864,"width":0.026761968,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Junk E-mail","depth":18,"bounds":{"left":0.36602393,"top":0.60055864,"width":0.026761968,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"219","depth":17,"bounds":{"left":0.41589096,"top":0.6017558,"width":0.005984043,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kontakty has menu","depth":17,"bounds":{"left":0.36602393,"top":0.6197127,"width":0.018450798,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontakty","depth":18,"bounds":{"left":0.36602393,"top":0.6197127,"width":0.018450798,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent Items has menu","depth":17,"bounds":{"left":0.36602393,"top":0.6388667,"width":0.022273935,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sent Items","depth":18,"bounds":{"left":0.36602393,"top":0.6388667,"width":0.022273935,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"WORK 848 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.65802073,"width":0.014461436,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"WORK","depth":18,"bounds":{"left":0.36602393,"top":0.65802073,"width":0.014461436,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"848","depth":17,"bounds":{"left":0.41522607,"top":0.6592179,"width":0.0066489363,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"z centra 1274 unread has menu","depth":17,"bounds":{"left":0.36602393,"top":0.6771748,"width":0.018118352,"height":0.014764565},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"z centra","depth":18,"bounds":{"left":0.36602393,"top":0.6771748,"width":0.018118352,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,274","depth":17,"bounds":{"left":0.41306517,"top":0.6783719,"width":0.00880984,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"bounds":{"left":0.34474733,"top":0.69393456,"width":0.07978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.36602393,"top":0.6963288,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Select","depth":12,"bounds":{"left":0.4351729,"top":0.11412609,"width":0.013297873,"height":0.015961692},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Refresh","depth":12,"bounds":{"left":0.45511967,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More email options","depth":12,"bounds":{"left":0.46841756,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show more messages","depth":13,"bounds":{"left":0.87732714,"top":0.10774142,"width":0.030917553,"height":0.028731046},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":15,"bounds":{"left":0.8799867,"top":0.11612131,"width":0.0016622341,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"–","depth":15,"bounds":{"left":0.88164896,"top":0.11612131,"width":0.002493351,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"50","depth":15,"bounds":{"left":0.8841423,"top":0.11612131,"width":0.0048204786,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"of","depth":15,"bounds":{"left":0.88896275,"top":0.11612131,"width":0.005817819,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21,145","depth":15,"bounds":{"left":0.8947806,"top":0.11612131,"width":0.010804521,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Newer","depth":13,"bounds":{"left":0.91223407,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Older","depth":13,"bounds":{"left":0.9255319,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle split pane mode","depth":12,"bounds":{"left":0.9388298,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Input tools on/off (Ctrl-Shift-K)","depth":14,"bounds":{"left":0.9574468,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Select input tool","depth":14,"bounds":{"left":0.9640958,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversations","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversations","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Primary","depth":15,"bounds":{"left":0.42985374,"top":0.14126097,"width":0.084109046,"height":0.03830806},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Primary","depth":19,"bounds":{"left":0.44714096,"top":0.1528332,"width":0.016954787,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Promotions, 50 new messages,","depth":15,"bounds":{"left":0.51396275,"top":0.14126097,"width":0.084109046,"height":0.03830806},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"50 new","depth":19,"bounds":{"left":0.56017286,"top":0.15403032,"width":0.013630319,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Promotions","depth":19,"bounds":{"left":0.53125,"top":0.1528332,"width":0.024933511,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Social, 25 new messages,","depth":15,"bounds":{"left":0.5980718,"top":0.14126097,"width":0.084109046,"height":0.03830806},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25 new","depth":19,"bounds":{"left":0.63248,"top":0.15403032,"width":0.013297873,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Social","depth":19,"bounds":{"left":0.61535907,"top":0.1528332,"width":0.013131649,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updates","depth":15,"bounds":{"left":0.6821808,"top":0.14126097,"width":0.084109046,"height":0.03830806},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates","depth":19,"bounds":{"left":0.6994681,"top":0.1528332,"width":0.018284574,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.","depth":18,"bounds":{"left":0.4351729,"top":0.18276137,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"bounds":{"left":0.44514626,"top":0.18276137,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Important because it matched one of your importance filters.","depth":18,"bounds":{"left":0.45511967,"top":0.18276137,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notion Team","depth":20,"bounds":{"left":0.46509308,"top":0.18355946,"width":0.026595745,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏","depth":18,"bounds":{"left":0.5315825,"top":0.18276137,"width":0.41323137,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Get a first look at our developer tools","depth":22,"bounds":{"left":0.5315825,"top":0.18355946,"width":0.078125,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"bounds":{"left":0.6097075,"top":0.18355946,"width":0.004488032,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏","depth":21,"bounds":{"left":0.61419547,"top":0.18355946,"width":0.18417554,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:45","depth":19,"bounds":{"left":0.9662567,"top":0.18475658,"width":0.009807181,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.","depth":18,"bounds":{"left":0.4351729,"top":0.20510775,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"bounds":{"left":0.44514626,"top":0.20510775,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Not important","depth":18,"bounds":{"left":0.45511967,"top":0.20510775,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CircleCI Builds","depth":20,"bounds":{"left":0.46509308,"top":0.20590582,"width":0.030418882,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to","depth":18,"bounds":{"left":0.5315825,"top":0.20510775,"width":0.41323137,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification","depth":22,"bounds":{"left":0.5315825,"top":0.20590582,"width":0.18783244,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"bounds":{"left":0.7194149,"top":0.20590582,"width":0.004488032,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to","depth":21,"bounds":{"left":0.72390294,"top":0.20590582,"width":0.27609706,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:40","depth":19,"bounds":{"left":0.96575797,"top":0.20710295,"width":0.010305851,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.","depth":18,"bounds":{"left":0.4351729,"top":0.22745411,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Not starred","depth":18,"bounds":{"left":0.44514626,"top":0.22745411,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Not important","depth":18,"bounds":{"left":0.45511967,"top":0.22745411,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"switch","subrole":"AXSwitch","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"imot.bg","depth":20,"bounds":{"left":0.46509308,"top":0.22825219,"width":0.015957447,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено","depth":18,"bounds":{"left":0.5315825,"top":0.22745411,"width":0.41323137,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Известяване за промяна в цена от imot.bg","depth":22,"bounds":{"left":0.5315825,"top":0.22825219,"width":0.092586435,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"bounds":{"left":0.6241689,"top":0.22825219,"width":0.004488032,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено","depth":21,"bounds":{"left":0.6286569,"top":0.22825219,"width":0.37134308,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
291121732012838241
|
-9171883464535172399
|
idle
|
accessibility
|
NULL
|
DXP4800PLUS-B5F8
5 Signs You Have Successfully Hur DXP4800PLUS-B5F8
5 Signs You Have Successfully Hurt a Narcissist; - [EMAIL] - Gmail
(67) Inbox | [EMAIL] | Proton Mail
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Western Digital Red Plus 3.5 6TB 5400rpm 256MB SATA3 (WD60EFPX) от 241,72 € (472,76 лв.) Вътрешен хард диск Western Digital - Pazaruvaj.com
Today's Deals
Today's Deals
architecture - screenpipe docs
architecture - screenpipe docs
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
[CircleCI] Workflow failed: jiminny / app on JY-20157-AJ-report-not-send-notification - [EMAIL] - Gmail
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude Platform
Claude Platform
rescue time detailed overview - Google Search
rescue time detailed overview - Google Search
Hey @louis030195 Ill check during my - screenpipe.com
Hey @louis030195 Ill check during my - screenpipe.com
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
GitHub - screenpipe/screenpipe: Run agents that work for you based on what you do. AI finally knows what you are doing · GitHub
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
Gong Pricing in 2026: Costs, Plans & Is It Worth It?
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Mute tab
(132) Japan Just PROVED They Can WIPE Out China Anytime, Anywhere - YouTube
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
None selected
Skip to content
Skip to content
Using Gmail with screen readers
Using Gmail with screen readers
Main menu
Gmail
Search
Search
Search mail
Advanced search options
Search mail
Support
Settings
Ask Gemini
Google apps
Google Account: Lukáš Koválik ([EMAIL]), Storage usage alert
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 7 unread
Drafts
7
Purchases has menu
Purchases
Social 5165 unread has menu
Social
5,165
Updates 8687 unread has menu
Updates
8,687
Forums 6048 unread has menu
Forums
6,048
Promotions 38629 unread has menu
Promotions
38,629
More labels
More
Labels
Labels
Create new label
Labels
Labels
[Imap]/Nevyžiadaná pošta has menu
[Imap]/Nevyžiadaná pošta
arch has menu
arch
Deleted Items has menu
Deleted Items
Fibank 1229 unread has menu
Fibank
1,229
FL 6 unread has menu
FL
6
Hardware & Software has menu
Hardware & Software
HOSTING 5 unread has menu
HOSTING
5
Infected Items has menu
Infected Items
jiminny-github 7421 unread has menu
jiminny-github
7,421
Junk E-mail 219 unread has menu
Junk E-mail
219
Kontakty has menu
Kontakty
Sent Items has menu
Sent Items
WORK 848 unread has menu
WORK
848
z centra 1274 unread has menu
z centra
1,274
More labels
More
Select
Refresh
More email options
Show more messages
1
–
50
of
21,145
Newer
Older
Toggle split pane mode
Input tools on/off (Ctrl-Shift-K)
Select input tool
Conversations
Conversations
Primary
Primary
Promotions, 50 new messages,
50 new
Promotions
Social, 25 new messages,
25 new
Social
Updates
Updates
Notion Team, Get a first look at our developer tools, 10:45, Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏.
Not starred
Important because it matched one of your importance filters.
Notion Team
Get a first look at our developer tools - Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
Get a first look at our developer tools
-
Join us for a special virtual event on May 13 ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏ ͏
10:45
CircleCI Builds, [CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification, 10:40, app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to.
Not starred
Not important
CircleCI Builds
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification - app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
[CircleCI] Workflow canceled: jiminny / app on JY-20157-AJ-report-not-send-notification
-
app / build_accept_deploy jiminny / app 2026-04-24T07:38:38Z JY-20157-AJ-report-not-send-notification #57700 Commit push by Lukas Kovalik (LakyLak) 2b160b5 JY-20157 move user pilot tracking changes to
10:40
imot.bg, Известяване за промяна в цена от imot.bg, 09:03, Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено.
Not starred
Not important
imot.bg
Известяване за промяна в цена от imot.bg - Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено
Известяване за промяна в цена от imot.bg
-
Imot.bg – Сайт №1 за имоти Здравейте, Има нови известия за промяна на цена от обявите в бележника Ви в imot.bg: Продава КЪЩА, област Перник, с. Големо Бучино: стара цена 265000 EURЦената е с включено...
|
76506
|
|
76578
|
NULL
|
0
|
2026-04-24T08:09:36.229593+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018176229_m1.jpg...
|
Firefox
|
[JY-20543] AJ Reports > Tracking - Jira — Work
|
True
|
jiminny.atlassian.net/browse/JY-20543?search_id=f4 jiminny.atlassian.net/browse/JY-20543?search_id=f484c0ee-9edf-42e1-8cff-52c73f5b3a7e&referrer=quick-find...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
[JY-20543] AJ Reports > Tracking - Jira
JY-2048 [JY-20543] AJ Reports > Tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
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
tracking
tracking
Create
Create
Rovo Ask Rovo
Ask Rovo
1 Notification
1 Notification
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
SE Kanban
SE Kanban
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
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New) Jiminny (New)
Jiminny (New)
/
Epic - Change parent
JY-19240
JY-19240
/
Story - Change work type
JY-20543
JY-20543
Copy link
AJ Reports > Tracking- Summary, edit
AJ Reports > Tracking
AJ Reports > Tracking
Add or create work related to this Story
Add or create work related to this Story
View app actions
View app actions
Collapse Description Description
Collapse Description
Collapse Description
Description
Edit Description, edit
We want to be able to track the usage of the
AJ
reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.
track each generated reports in
DD
- include company name and frequency
for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report
for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list
note: for UP you can see how we currently track events such as Logged-activity, Held-conference
Subtasks
Subtasks
Add subtask
Add subtask
Linked work items
Linked work items
Add linked work item
Add linked work item
Collapse Activity Activity
Collapse Activity
Collapse Activity
Activity
All
All
Comments
Comments
History
History
Work log
Work log
Atlassian Intelligence Summarise
Summarise
Newest first Newest first
Newest first
Add a comment…
Suggest a reply...
Suggest a reply...
Status update...
Status update...
Thanks...
Thanks...
Pro tip:
press
M
to comment
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:41
BE: 1 d
Reply
Add thumbs up reaction
Add reaction...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":9,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"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,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"tracking","depth":11,"value":"tracking","help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tracking","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"1 Notification","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Notification","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"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,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"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,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Recent","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Starred","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"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":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"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":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"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":18,"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More spaces","depth":17,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"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 Filters","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"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 Dashboards","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"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 Operations","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New) Jiminny (New)","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Epic - Change parent","depth":15,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"JY-19240","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-19240","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Story - Change work type","depth":15,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"JY-20543","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy link","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AJ Reports > Tracking- Summary, edit","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AJ Reports > Tracking","depth":11,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AJ Reports > Tracking","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add or create work related to this Story","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add or create work related to this Story","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"View app actions","depth":12,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View app actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Collapse Description Description","depth":11,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Description","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse Description","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit Description, edit","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"We want to be able to track the usage of the","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AJ","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"track each generated reports in","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DD","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"- include company name and frequency","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"note: for UP you can see how we currently track events such as Logged-activity, Held-conference","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Subtasks","depth":11,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Subtasks","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add subtask","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add subtask","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Linked work items","depth":11,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Linked work items","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add linked work item","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add linked work item","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Collapse Activity Activity","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Activity","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse Activity","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All","depth":14,"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Comments","depth":14,"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Comments","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"History","depth":14,"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"History","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Work log","depth":14,"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Work log","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Atlassian Intelligence Summarise","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarise","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Newest first Newest first","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Newest first","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add a comment…","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Suggest a reply...","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Suggest a reply...","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Status update...","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status update...","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Thanks...","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Thanks...","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pro tip:","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"press","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"M","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to comment","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"More information about Nikolay Nikolov","depth":18,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More information about Nikolay Nikolov","depth":20,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy link to comment","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 March 2026 at 14:41","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BE: 1 d","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reply","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Add thumbs up reaction","depth":17,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Add reaction","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3256029897040732127
|
1662212697442966222
|
click
|
accessibility
|
NULL
|
[JY-20543] AJ Reports > Tracking - Jira
JY-2048 [JY-20543] AJ Reports > Tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
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
tracking
tracking
Create
Create
Rovo Ask Rovo
Ask Rovo
1 Notification
1 Notification
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
SE Kanban
SE Kanban
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
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New) Jiminny (New)
Jiminny (New)
/
Epic - Change parent
JY-19240
JY-19240
/
Story - Change work type
JY-20543
JY-20543
Copy link
AJ Reports > Tracking- Summary, edit
AJ Reports > Tracking
AJ Reports > Tracking
Add or create work related to this Story
Add or create work related to this Story
View app actions
View app actions
Collapse Description Description
Collapse Description
Collapse Description
Description
Edit Description, edit
We want to be able to track the usage of the
AJ
reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.
track each generated reports in
DD
- include company name and frequency
for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report
for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list
note: for UP you can see how we currently track events such as Logged-activity, Held-conference
Subtasks
Subtasks
Add subtask
Add subtask
Linked work items
Linked work items
Add linked work item
Add linked work item
Collapse Activity Activity
Collapse Activity
Collapse Activity
Activity
All
All
Comments
Comments
History
History
Work log
Work log
Atlassian Intelligence Summarise
Summarise
Newest first Newest first
Newest first
Add a comment…
Suggest a reply...
Suggest a reply...
Status update...
Status update...
Thanks...
Thanks...
Pro tip:
press
M
to comment
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:41
BE: 1 d
Reply
Add thumbs up reaction
Add reaction...
|
NULL
|
|
76579
|
NULL
|
0
|
2026-04-24T08:09:36.358028+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018176358_m2.jpg...
|
Firefox
|
[JY-20543] AJ Reports > Tracking - Jira — Work
|
True
|
jiminny.atlassian.net/browse/JY-20543?search_id=f4 jiminny.atlassian.net/browse/JY-20543?search_id=f484c0ee-9edf-42e1-8cff-52c73f5b3a7e&referrer=quick-find...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
[JY-20543] AJ Reports > Tracking - Jira
JY-2048 [JY-20543] AJ Reports > Tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
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
tracking
tracking
Create
Create
Rovo Ask Rovo
Ask Rovo
1 Notification
1 Notification
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
SE Kanban
SE Kanban
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
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New) Jiminny (New)
Jiminny (New)
/
Epic - Change parent
JY-19240
JY-19240
/
Story - Change work type
JY-20543
JY-20543
Copy link
AJ Reports > Tracking- Summary, edit
AJ Reports > Tracking
AJ Reports > Tracking
Add or create work related to this Story
Add or create work related to this Story
View app actions
View app actions
Collapse Description Description
Collapse Description
Collapse Description
Description
Edit Description, edit
We want to be able to track the usage of the
AJ
reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.
track each generated reports in
DD
- include company name and frequency
for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report
for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list
note: for UP you can see how we currently track events such as Logged-activity, Held-conference
Subtasks
Subtasks
Add subtask
Add subtask
Linked work items
Linked work items
Add linked work item
Add linked work item
Collapse Activity Activity
Collapse Activity
Collapse Activity
Activity
All
All
Comments
Comments
History
History
Work log
Work log
Atlassian Intelligence Summarise
Summarise
Newest first Newest first
Newest first
Add a comment…
Suggest a reply...
Suggest a reply...
Status update...
Status update...
Thanks...
Thanks...
Pro tip:
press
M
to comment
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:41
BE: 1 d
Reply
Add thumbs up reaction
Add reaction
Edit
More actions
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:38
Where
public function pushToDatadog
- push to
UserPilot 1 entry for the creator
Reply...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.23703113,"width":0.16356383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.2697526,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.07679521,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.32130983,"top":0.07861133,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":10,"bounds":{"left":0.32130983,"top":0.097765364,"width":0.016954787,"height":0.01396648},"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.32130983,"top":0.097765364,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":10,"bounds":{"left":0.32130983,"top":0.11691939,"width":0.016954787,"height":0.01396648},"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.32130983,"top":0.11691939,"width":0.016954787,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":10,"bounds":{"left":0.32130983,"top":0.13607343,"width":0.029421542,"height":0.01396648},"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.32130983,"top":0.13607343,"width":0.029421542,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":9,"bounds":{"left":0.3146609,"top":0.057861134,"width":0.010638298,"height":0.025538707},"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.31981382,"top":0.06344773,"width":0.039727394,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":10,"bounds":{"left":0.32662898,"top":0.057861134,"width":0.010638298,"height":0.025538707},"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.33178192,"top":0.06344773,"width":0.044215426,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":9,"bounds":{"left":0.33992687,"top":0.057861134,"width":0.029421542,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"tracking","depth":11,"bounds":{"left":0.52011305,"top":0.06264964,"width":0.24268617,"height":0.015961692},"value":"tracking","help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tracking","depth":12,"bounds":{"left":0.52011305,"top":0.06384677,"width":0.017785905,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create","depth":10,"bounds":{"left":0.77111036,"top":0.057861134,"width":0.030086435,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":12,"bounds":{"left":0.78241354,"top":0.06384677,"width":0.014793883,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":12,"bounds":{"left":0.9119016,"top":0.057861134,"width":0.035904255,"height":0.025538707},"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.9232048,"top":0.06384677,"width":0.020611702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"1 Notification","depth":12,"bounds":{"left":0.94913566,"top":0.057861134,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Notification","depth":14,"bounds":{"left":0.95428854,"top":0.06344773,"width":0.028590426,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":12,"bounds":{"left":0.96110374,"top":0.057861134,"width":0.010638298,"height":0.025538707},"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.9662567,"top":0.06344773,"width":0.010139627,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":12,"bounds":{"left":0.9730718,"top":0.057861134,"width":0.010638298,"height":0.025538707},"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.97822475,"top":0.06344773,"width":0.017952127,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.9850399,"top":0.057861134,"width":0.010638298,"height":0.025538707},"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,"bounds":{"left":0.99019283,"top":0.06344773,"width":0.009807169,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":12,"bounds":{"left":0.3146609,"top":0.09976058,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":15,"bounds":{"left":0.3252992,"top":0.10574621,"width":0.01662234,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Recent","depth":12,"bounds":{"left":0.3146609,"top":0.12529927,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":15,"bounds":{"left":0.3252992,"top":0.13128492,"width":0.015458777,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Starred","depth":12,"bounds":{"left":0.3146609,"top":0.15083799,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":15,"bounds":{"left":0.3252992,"top":0.15682362,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":12,"bounds":{"left":0.3146609,"top":0.1763767,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":15,"bounds":{"left":0.3252992,"top":0.18236233,"width":0.011635638,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":13,"bounds":{"left":0.38414228,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"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":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":12,"bounds":{"left":0.3146609,"top":0.2019154,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":15,"bounds":{"left":0.3252992,"top":0.20790103,"width":0.016456118,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":13,"bounds":{"left":0.36751994,"top":0.20510775,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":13,"bounds":{"left":0.37682846,"top":0.20510775,"width":0.007978723,"height":0.01915403},"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":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":16,"bounds":{"left":0.32064494,"top":0.23423783,"width":0.013464096,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":17,"bounds":{"left":0.31865028,"top":0.2529928,"width":0.0674867,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":20,"bounds":{"left":0.32928857,"top":0.25897846,"width":0.032081116,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":18,"bounds":{"left":0.31998006,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":18,"bounds":{"left":0.36751994,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":18,"bounds":{"left":0.37682846,"top":0.25618514,"width":0.007978723,"height":0.01915403},"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":19,"bounds":{"left":0.3226396,"top":0.27853152,"width":0.06349734,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":22,"bounds":{"left":0.3332779,"top":0.28451717,"width":0.032247342,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.38414228,"top":0.28172386,"width":0.0039893617,"height":0.01915403},"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":19,"bounds":{"left":0.3226396,"top":0.30407023,"width":0.06349734,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":22,"bounds":{"left":0.3332779,"top":0.31005585,"width":0.024102394,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.38414228,"top":0.30726257,"width":0.0039893617,"height":0.01915403},"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":19,"bounds":{"left":0.3226396,"top":0.32960895,"width":0.06349734,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":22,"bounds":{"left":0.3332779,"top":0.33559456,"width":0.03125,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.38414228,"top":0.33280128,"width":0.0039893617,"height":0.01915403},"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":19,"bounds":{"left":0.3226396,"top":0.35514766,"width":0.06349734,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":22,"bounds":{"left":0.3332779,"top":0.36113328,"width":0.050531916,"height":0.030726258},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.38414228,"top":0.35834,"width":0.0039893617,"height":0.01915403},"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":19,"bounds":{"left":0.3226396,"top":0.38068634,"width":0.06349734,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":22,"bounds":{"left":0.3332779,"top":0.386672,"width":0.038231384,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":20,"bounds":{"left":0.38414228,"top":0.38387868,"width":0.0039893617,"height":0.01915403},"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":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":17,"bounds":{"left":0.31865028,"top":0.40622506,"width":0.0674867,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":20,"bounds":{"left":0.32928857,"top":0.4122107,"width":0.03025266,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":18,"bounds":{"left":0.3854721,"top":0.4094174,"width":0.0039893617,"height":0.01915403},"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":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More spaces","depth":17,"bounds":{"left":0.31865028,"top":0.43176377,"width":0.0674867,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":20,"bounds":{"left":0.32928857,"top":0.43774942,"width":0.028756648,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":12,"bounds":{"left":0.3146609,"top":0.45730248,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":15,"bounds":{"left":0.3252992,"top":0.4632881,"width":0.013796543,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":13,"bounds":{"left":0.38414228,"top":0.46049482,"width":0.0039893617,"height":0.01915403},"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 Filters","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":12,"bounds":{"left":0.3146609,"top":0.4828412,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":15,"bounds":{"left":0.3252992,"top":0.4888268,"width":0.026761968,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":13,"bounds":{"left":0.38613698,"top":0.48603353,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":13,"bounds":{"left":0.3934508,"top":0.48603353,"width":0.0039893617,"height":0.01915403},"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 Dashboards","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":12,"bounds":{"left":0.3146609,"top":0.5083799,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":15,"bounds":{"left":0.3252992,"top":0.5143655,"width":0.02443484,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Operations","depth":13,"bounds":{"left":0.38414228,"top":0.51157224,"width":0.0039893617,"height":0.01915403},"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 Operations","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Confluence , (opens new window)","depth":13,"bounds":{"left":0.3146609,"top":0.5434956,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Confluence","depth":17,"bounds":{"left":0.3252992,"top":0.5494813,"width":0.025764627,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"bounds":{"left":0.3146609,"top":0.55706304,"width":0.04837101,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Teams , (opens new window)","depth":13,"bounds":{"left":0.3146609,"top":0.56903434,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Teams","depth":17,"bounds":{"left":0.3252992,"top":0.57501996,"width":0.014793883,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", (opens new window)","depth":15,"bounds":{"left":0.3146609,"top":0.5826017,"width":0.04837101,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"open menu","depth":14,"bounds":{"left":0.37483376,"top":0.57222664,"width":0.0039893617,"height":0.01915403},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"open menu","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Customise sidebar","depth":12,"bounds":{"left":0.3146609,"top":0.60415006,"width":0.071476065,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customise sidebar","depth":15,"bounds":{"left":0.3252992,"top":0.6101357,"width":0.04155585,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Resize side navigation panel","depth":13,"bounds":{"left":0.44198802,"top":0.0981644,"width":0.062333778,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Spaces","depth":15,"bounds":{"left":0.40242687,"top":0.10933759,"width":0.013962766,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Spaces","depth":17,"bounds":{"left":0.40242687,"top":0.11292897,"width":0.013962766,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"bounds":{"left":0.41821808,"top":0.11173184,"width":0.0016622341,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New) Jiminny (New)","depth":15,"bounds":{"left":0.42370346,"top":0.10933759,"width":0.034574468,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":17,"bounds":{"left":0.43101728,"top":0.11292897,"width":0.027260639,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"bounds":{"left":0.46010637,"top":0.11173184,"width":0.0016622341,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Epic - Change parent","depth":15,"bounds":{"left":0.4635971,"top":0.10933759,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"JY-19240","depth":15,"bounds":{"left":0.4715758,"top":0.10933759,"width":0.017952127,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-19240","depth":17,"bounds":{"left":0.4715758,"top":0.11292897,"width":0.017952127,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"bounds":{"left":0.49135637,"top":0.11173184,"width":0.0016622341,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Story - Change work type","depth":15,"bounds":{"left":0.4948471,"top":0.10933759,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"JY-20543","depth":15,"bounds":{"left":0.5028258,"top":0.10933759,"width":0.018783245,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20543","depth":17,"bounds":{"left":0.5028258,"top":0.11292897,"width":0.018783245,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy link","depth":16,"bounds":{"left":0.5202792,"top":0.11213089,"width":0.005319149,"height":0.012769354},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AJ Reports > Tracking- Summary, edit","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"AJ Reports > Tracking","depth":11,"bounds":{"left":0.40309176,"top":0.1396648,"width":0.0831117,"height":0.022346368},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AJ Reports > Tracking","depth":12,"bounds":{"left":0.40309176,"top":0.13926576,"width":0.0831117,"height":0.023543496},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Add or create work related to this Story","depth":12,"bounds":{"left":0.40242687,"top":0.17158818,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add or create work related to this Story","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"View app actions","depth":12,"bounds":{"left":0.41572472,"top":0.17158818,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"View app actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Collapse Description Description","depth":11,"bounds":{"left":0.39444813,"top":0.20989625,"width":0.4537899,"height":0.025538707},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Description","depth":13,"bounds":{"left":0.39311835,"top":0.21308859,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse Description","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":14,"bounds":{"left":0.40242687,"top":0.2150838,"width":0.029587766,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit Description, edit","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"We want to be able to track the usage of the","depth":14,"bounds":{"left":0.40309176,"top":0.23982441,"width":0.09857048,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AJ","depth":15,"bounds":{"left":0.50166225,"top":0.23982441,"width":0.005817819,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.","depth":14,"bounds":{"left":0.50748,"top":0.23982441,"width":0.28773272,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"track each generated reports in","depth":16,"bounds":{"left":0.41107047,"top":0.26855546,"width":0.07047872,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DD","depth":17,"bounds":{"left":0.4815492,"top":0.26855546,"width":0.0068151597,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"- include company name and frequency","depth":16,"bounds":{"left":0.48836437,"top":0.26855546,"width":0.08892952,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report","depth":16,"bounds":{"left":0.41107047,"top":0.29090184,"width":0.29388297,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list","depth":16,"bounds":{"left":0.41107047,"top":0.31324822,"width":0.24650931,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"note: for UP you can see how we currently track events such as Logged-activity, Held-conference","depth":14,"bounds":{"left":0.40309176,"top":0.34197924,"width":0.21575798,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Subtasks","depth":11,"bounds":{"left":0.40242687,"top":0.39984038,"width":0.023936171,"height":0.015961692},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Subtasks","depth":12,"bounds":{"left":0.40242687,"top":0.40023944,"width":0.023936171,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add subtask","depth":12,"bounds":{"left":0.3984375,"top":0.42059058,"width":0.035405584,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add subtask","depth":14,"bounds":{"left":0.40242687,"top":0.42657623,"width":0.027426861,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Linked work items","depth":11,"bounds":{"left":0.40242687,"top":0.46528333,"width":0.04654255,"height":0.015961692},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Linked work items","depth":12,"bounds":{"left":0.40242687,"top":0.46568236,"width":0.04654255,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add linked work item","depth":12,"bounds":{"left":0.3984375,"top":0.48443735,"width":0.05418883,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add linked work item","depth":14,"bounds":{"left":0.40242687,"top":0.490423,"width":0.046210106,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Collapse Activity Activity","depth":12,"bounds":{"left":0.39444813,"top":0.5291301,"width":0.4537899,"height":0.025538707},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse Activity","depth":14,"bounds":{"left":0.39311835,"top":0.5323224,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse Activity","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity","depth":15,"bounds":{"left":0.40242687,"top":0.5343176,"width":0.019946808,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All","depth":14,"bounds":{"left":0.4034242,"top":0.5602554,"width":0.01412899,"height":0.0207502},"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All","depth":16,"bounds":{"left":0.40774602,"top":0.56384677,"width":0.005485372,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Comments","depth":14,"bounds":{"left":0.41821808,"top":0.5602554,"width":0.032413565,"height":0.0207502},"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Comments","depth":16,"bounds":{"left":0.4225399,"top":0.56384677,"width":0.023769947,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"History","depth":14,"bounds":{"left":0.45129654,"top":0.5602554,"width":0.024268618,"height":0.0207502},"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"History","depth":16,"bounds":{"left":0.45561835,"top":0.56384677,"width":0.015625,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Work log","depth":14,"bounds":{"left":0.47623006,"top":0.5602554,"width":0.02825798,"height":0.0207502},"help_text":"","role_description":"radio button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Work log","depth":16,"bounds":{"left":0.48055187,"top":0.56384677,"width":0.019614361,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Atlassian Intelligence Summarise","depth":14,"bounds":{"left":0.829621,"top":0.5642458,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarise","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Newest first Newest first","depth":13,"bounds":{"left":0.8402593,"top":0.5642458,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Newest first","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add a comment…","depth":15,"bounds":{"left":0.4163896,"top":0.60415006,"width":0.43118352,"height":0.07182761},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Suggest a reply...","depth":17,"bounds":{"left":0.42237368,"top":0.6424581,"width":0.046708778,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Suggest a reply...","depth":19,"bounds":{"left":0.42636302,"top":0.6452514,"width":0.03873005,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Status update...","depth":17,"bounds":{"left":0.47041222,"top":0.6424581,"width":0.04305186,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status update...","depth":19,"bounds":{"left":0.4744016,"top":0.6452514,"width":0.03507314,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Thanks...","depth":17,"bounds":{"left":0.5147939,"top":0.6424581,"width":0.028590426,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Thanks...","depth":19,"bounds":{"left":0.5187833,"top":0.6452514,"width":0.020611702,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pro tip:","depth":16,"bounds":{"left":0.41572472,"top":0.6843575,"width":0.013796543,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"press","depth":15,"bounds":{"left":0.42952126,"top":0.6843575,"width":0.012632979,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"M","depth":17,"bounds":{"left":0.44348404,"top":0.68515563,"width":0.0034906915,"height":0.011173184},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to comment","depth":15,"bounds":{"left":0.44830453,"top":0.6843575,"width":0.023603724,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"More information about Nikolay Nikolov","depth":18,"bounds":{"left":0.42104387,"top":0.7067039,"width":0.034906916,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More information about Nikolay Nikolov","depth":20,"bounds":{"left":0.42104387,"top":0.7067039,"width":0.034906916,"height":0.019553073},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":21,"bounds":{"left":0.42104387,"top":0.71109337,"width":0.034906916,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy link to comment","depth":18,"bounds":{"left":0.45728058,"top":0.7094972,"width":0.005319149,"height":0.012769354},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 March 2026 at 14:41","depth":19,"bounds":{"left":0.42104387,"top":0.72625697,"width":0.044215426,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BE: 1 d","depth":19,"bounds":{"left":0.42104387,"top":0.7509976,"width":0.01462766,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reply","depth":17,"bounds":{"left":0.42104387,"top":0.77693534,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Add thumbs up reaction","depth":17,"bounds":{"left":0.43168217,"top":0.77693534,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Add reaction","depth":17,"bounds":{"left":0.44232047,"top":0.77693534,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":17,"bounds":{"left":0.45295876,"top":0.77693534,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More actions","depth":17,"bounds":{"left":0.4635971,"top":0.77693534,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"More information about Nikolay Nikolov","depth":18,"bounds":{"left":0.42104387,"top":0.8184357,"width":0.034906916,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More information about Nikolay Nikolov","depth":20,"bounds":{"left":0.42104387,"top":0.8184357,"width":0.034906916,"height":0.019553073},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":21,"bounds":{"left":0.42104387,"top":0.8228252,"width":0.034906916,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy link to comment","depth":18,"bounds":{"left":0.45728058,"top":0.82122904,"width":0.005319149,"height":0.012769354},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 March 2026 at 14:38","depth":19,"bounds":{"left":0.42104387,"top":0.83798885,"width":0.04504654,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Where","depth":19,"bounds":{"left":0.42104387,"top":0.86272943,"width":0.015791224,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function pushToDatadog","depth":20,"bounds":{"left":0.43799868,"top":0.8639266,"width":0.07081117,"height":0.0131683955},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"- push to","depth":19,"bounds":{"left":0.51013964,"top":0.86272943,"width":0.02244016,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"UserPilot 1 entry for the creator","depth":21,"bounds":{"left":0.4290226,"top":0.8850758,"width":0.06865027,"height":0.01396648},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reply","depth":17,"bounds":{"left":0.42104387,"top":0.91101354,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-5701469090799662515
|
1663338047592942286
|
click
|
accessibility
|
NULL
|
[JY-20543] AJ Reports > Tracking - Jira
JY-2048 [JY-20543] AJ Reports > Tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
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
tracking
tracking
Create
Create
Rovo Ask Rovo
Ask Rovo
1 Notification
1 Notification
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
SE Kanban
SE Kanban
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
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
More spaces
More spaces
Filters
Filters
More actions for Filters
More actions for Filters
Dashboards
Dashboards
Create dashboard
Create dashboard
More actions for Dashboards
More actions for Dashboards
Operations
Operations
More actions for Operations
More actions for Operations
Confluence , (opens new window)
Confluence
, (opens new window)
Teams , (opens new window)
Teams
, (opens new window)
open menu
open menu
Customise sidebar
Customise sidebar
Resize side navigation panel
Spaces
Spaces
/
Jiminny (New) Jiminny (New)
Jiminny (New)
/
Epic - Change parent
JY-19240
JY-19240
/
Story - Change work type
JY-20543
JY-20543
Copy link
AJ Reports > Tracking- Summary, edit
AJ Reports > Tracking
AJ Reports > Tracking
Add or create work related to this Story
Add or create work related to this Story
View app actions
View app actions
Collapse Description Description
Collapse Description
Collapse Description
Description
Edit Description, edit
We want to be able to track the usage of the
AJ
reports. We will use this to keep track of the adoption but also to use Userpilot tooltips to push users who are not using it to use it.
track each generated reports in
DD
- include company name and frequency
for AJ reports - track each generated report in UserPilot as an event on the user - track it only for the user who has created the report
for Exec reports - track each generated report - set the tracking for each user in the non-jiminny participants list
note: for UP you can see how we currently track events such as Logged-activity, Held-conference
Subtasks
Subtasks
Add subtask
Add subtask
Linked work items
Linked work items
Add linked work item
Add linked work item
Collapse Activity Activity
Collapse Activity
Collapse Activity
Activity
All
All
Comments
Comments
History
History
Work log
Work log
Atlassian Intelligence Summarise
Summarise
Newest first Newest first
Newest first
Add a comment…
Suggest a reply...
Suggest a reply...
Status update...
Status update...
Thanks...
Thanks...
Pro tip:
press
M
to comment
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:41
BE: 1 d
Reply
Add thumbs up reaction
Add reaction
Edit
More actions
More information about Nikolay Nikolov
More information about Nikolay Nikolov
Nikolay Nikolov
Copy link to comment
30 March 2026 at 14:38
Where
public function pushToDatadog
- push to
UserPilot 1 entry for the creator
Reply...
|
NULL
|
|
76655
|
NULL
|
0
|
2026-04-24T08:14:41.169865+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018481169_m1.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - 1 new item - Slack...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:11:46 AM
10:11 AM
но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък
Aneliya Angelova
Yesterday at 10:13:21 AM
10:13 AM
Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент
Lukas Kovalik
Yesterday at 10:13:47 AM
10:13 AM
да, ами добре ще ги сменя, на старите репорти
(edited)
Aneliya Angelova
Yesterday at 10:14:00 AM
10:14 AM
оки
Yesterday at 10:15:09 AM
10:15
тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:11:46 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:11 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:13:21 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:13:47 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, ами добре ще ги сменя, на старите репорти","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:14:00 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:14 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"оки","depth":23,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:15:09 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:15","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:47:31 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:47 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Nikolay Yankov","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:31:46 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:31 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"какво значи които са пратени?","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Yesterday at 1:32:17 PM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:35:32 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:35 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":21,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:13:41 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Adelina Petrova, Direct Message, 1 of 7 suggestions","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova is typing","depth":11,"role_description":"text"}]...
|
1670537004428059730
|
-3586248960455719342
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:11:46 AM
10:11 AM
но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък
Aneliya Angelova
Yesterday at 10:13:21 AM
10:13 AM
Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент
Lukas Kovalik
Yesterday at 10:13:47 AM
10:13 AM
да, ами добре ще ги сменя, на старите репорти
(edited)
Aneliya Angelova
Yesterday at 10:14:00 AM
10:14 AM
оки
Yesterday at 10:15:09 AM
10:15
тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Jump to date
New
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing
Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
|
76656
|
NULL
|
0
|
2026-04-24T08:14:41.340526+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018481340_m2.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - 1 new item - Slack...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:11:46 AM
10:11 AM
но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък
Aneliya Angelova
Yesterday at 10:13:21 AM
10:13 AM
Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент
Lukas Kovalik
Yesterday at 10:13:47 AM
10:13 AM
да, ами добре ще ги сменя, на старите репорти
(edited)
Aneliya Angelova
Yesterday at 10:14:00 AM
10:14 AM
оки
Yesterday at 10:15:09 AM
10:15
тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"bounds":{"left":0.042220745,"top":0.092577815,"width":0.03723404,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.114924185,"width":0.025598405,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"bounds":{"left":0.042220745,"top":0.13727055,"width":0.018949468,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.15961692,"width":0.015957447,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"bounds":{"left":0.042220745,"top":0.1819633,"width":0.029587766,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.20430966,"width":0.022938829,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"bounds":{"left":0.042220745,"top":0.22665602,"width":0.045212764,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"bounds":{"left":0.042220745,"top":0.2490024,"width":0.045877658,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"bounds":{"left":0.042220745,"top":0.27134877,"width":0.03125,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.29369512,"width":0.034906916,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.3160415,"width":0.03856383,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.33838788,"width":0.01662234,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.36073422,"width":0.01761968,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.3830806,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.40542698,"width":0.016954787,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.42777336,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.4501197,"width":0.04488032,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.5027933,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.07945479,"top":0.5027933,"width":0.0063164895,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.08211436,"top":0.5027933,"width":0.014295213,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.09607713,"top":0.5203512,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.09607713,"top":0.5203512,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.5251397,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"bounds":{"left":0.042220745,"top":0.547486,"width":0.034242023,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.5698324,"width":0.026263298,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.59217876,"width":0.030585106,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.61452514,"width":0.034906916,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.6368715,"width":0.032912236,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.042220745,"top":0.6592179,"width":0.034242023,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.6815643,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"bounds":{"left":0.042220745,"top":0.7039106,"width":0.034242023,"height":0.005586592},"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.033909574,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03523936,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.021609042,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.011635638,"height":0.0007980846},"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.10206117,"top":0.09177973,"width":0.030585106,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.01861702,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.13397606,"top":0.09177973,"width":0.033909574,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.021941489,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.16921543,"top":0.09177973,"width":0.020944148,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.17852394,"top":0.10055866,"width":0.008976064,"height":0.012769354},"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.19115691,"top":0.09177973,"width":0.010970744,"height":0.030327214},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.015625,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14660904,"top":0.12689546,"width":0.032579787,"height":0.022346368},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:11:46 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:11 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:13:21 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:13:47 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, ами добре ще ги сменя, на старите репорти","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:14:00 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:14 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"оки","depth":23,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:15:09 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:15","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега","depth":23,"bounds":{"left":0.11801862,"top":0.11572227,"width":0.09940159,"height":0.035913806},"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"bounds":{"left":0.11801862,"top":0.15961692,"width":0.030917553,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14860372,"top":0.16121309,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:47:31 AM","depth":22,"bounds":{"left":0.1512633,"top":0.16360734,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:47 AM","depth":23,"bounds":{"left":0.1512633,"top":0.16360734,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани","depth":23,"bounds":{"left":0.11801862,"top":0.17877094,"width":0.091755316,"height":0.08459697},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.14604948,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.14604948,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.14604948,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.14604948,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.14604948,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.14604948,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5744103644316845297
|
-3480905256510155238
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:11:46 AM
10:11 AM
но реално ако искаме ретроспективно да пуснем нещо седмично което не е минало в сряда ще е от среяда до четвъртък
Aneliya Angelova
Yesterday at 10:13:21 AM
10:13 AM
Галя казва, че по скоро иска винаги да се пускат от понеделник до неделя, за да може да има бекъп вариант ако трябва по някаква причина ръчно да се рерънне седмичен репорт на клиент
Lukas Kovalik
Yesterday at 10:13:47 AM
10:13 AM
да, ами добре ще ги сменя, на старите репорти
(edited)
Aneliya Angelova
Yesterday at 10:14:00 AM
10:14 AM
оки
Yesterday at 10:15:09 AM
10:15
тайтъла на репорта и Data Source секцията ще показват правилния период нали - понеже това се разминаваше до сега
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
76654
|
|
76740
|
NULL
|
0
|
2026-04-24T08:19:49.158465+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018789158_m1.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - 1 new item - Slack...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:47:31 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:47 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани","depth":23,"role_description":"text"},{"role":"AXButton","text":"Nikolay Yankov","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:31:46 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:31 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"какво значи които са пратени?","depth":23,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:32:17 PM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:35:32 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:35 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:13:41 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:05 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"седмични не са ли в понеделник само","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:19 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:15:56 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:08 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"без да се съобразява далки е дневен или седмичен или месечен","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:16:37 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"а да, за пращане мисля че няма проверки","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:56 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"чакай да видя, мисля че само при генериране","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":20,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:18:33 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:18 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Иначе ако това е обяснението - нека така си остане.","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Adelina Petrova, Direct Message, 1 of 7 suggestions","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova is typing","depth":11,"role_description":"text"}]...
|
-666114593636527653
|
-3586248686131838894
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing
Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
|
76741
|
NULL
|
0
|
2026-04-24T08:19:49.155141+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777018789155_m2.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - 1 new item - Slack...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"bounds":{"left":0.042220745,"top":0.092577815,"width":0.03723404,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.114924185,"width":0.025598405,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"bounds":{"left":0.042220745,"top":0.13727055,"width":0.018949468,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.15961692,"width":0.015957447,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"bounds":{"left":0.042220745,"top":0.1819633,"width":0.029587766,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.20430966,"width":0.022938829,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"bounds":{"left":0.042220745,"top":0.22665602,"width":0.045212764,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"bounds":{"left":0.042220745,"top":0.2490024,"width":0.045877658,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"bounds":{"left":0.042220745,"top":0.27134877,"width":0.03125,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.29369512,"width":0.034906916,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.3160415,"width":0.03856383,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.33838788,"width":0.01662234,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.36073422,"width":0.01761968,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.3830806,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.40542698,"width":0.016954787,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.42777336,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.4501197,"width":0.04488032,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.5027933,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.07945479,"top":0.5027933,"width":0.0063164895,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.08211436,"top":0.5027933,"width":0.014295213,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.09607713,"top":0.5203512,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.09607713,"top":0.5203512,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.5251397,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"bounds":{"left":0.042220745,"top":0.547486,"width":0.034242023,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.5698324,"width":0.026263298,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.59217876,"width":0.030585106,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.61452514,"width":0.034906916,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.6368715,"width":0.032912236,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.042220745,"top":0.6592179,"width":0.034242023,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.6815643,"width":0.03756649,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"bounds":{"left":0.042220745,"top":0.7039106,"width":0.034242023,"height":0.005586592},"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.033909574,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03523936,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.021609042,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.011635638,"height":0.0007980846},"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.10206117,"top":0.09177973,"width":0.030585106,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.01861702,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.13397606,"top":0.09177973,"width":0.033909574,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.021941489,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.16921543,"top":0.09177973,"width":0.020944148,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.17852394,"top":0.10055866,"width":0.008976064,"height":0.012769354},"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.19115691,"top":0.09177973,"width":0.010970744,"height":0.030327214},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.015625,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.14660904,"top":0.12689546,"width":0.032579787,"height":0.022346368},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 10:47:31 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:47 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани","depth":23,"role_description":"text"},{"role":"AXButton","text":"Nikolay Yankov","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:31:46 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:31 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"какво значи които са пратени?","depth":23,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:32:17 PM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:32","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:35:32 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:35 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика","depth":23,"bounds":{"left":0.11801862,"top":0.11572227,"width":0.102726065,"height":0.03431764},"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.15226063,"top":0.13727055,"width":0.0013297872,"height":0.012769354},"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"bounds":{"left":0.15359043,"top":0.13727055,"width":0.014295213,"height":0.012769354},"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.16788563,"top":0.13727055,"width":0.0009973404,"height":0.012769354},"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.15026596,"top":0.1660016,"width":0.025265958,"height":0.022346368},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.11801862,"top":0.1971269,"width":0.038896278,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.15658244,"top":0.19872306,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:13:41 AM","depth":22,"bounds":{"left":0.15924202,"top":0.20111732,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:13 AM","depth":23,"bounds":{"left":0.15924202,"top":0.20111732,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.","depth":23,"bounds":{"left":0.11801862,"top":0.21628092,"width":0.10239362,"height":0.049481247},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.18355946,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.18355946,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.18355946,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.18355946,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.18355946,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.18355946,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.18355946,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.18355946,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"bounds":{"left":0.11801862,"top":0.273743,"width":0.030917553,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14860372,"top":0.2753392,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:05 AM","depth":22,"bounds":{"left":0.1512633,"top":0.27773345,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"bounds":{"left":0.1512633,"top":0.27773345,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"седмични не са ли в понеделник само","depth":23,"bounds":{"left":0.11801862,"top":0.29289705,"width":0.08809841,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.2601756,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.2601756,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.2601756,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.2601756,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.2601756,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.2601756,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.2601756,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.2601756,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.11801862,"top":0.31524342,"width":0.038896278,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.15658244,"top":0.31683958,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:19 AM","depth":22,"bounds":{"left":0.15924202,"top":0.31923383,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"bounds":{"left":0.15924202,"top":0.31923383,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"bounds":{"left":0.11801862,"top":0.33439744,"width":0.0056515955,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.30167598,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.30167598,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.30167598,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.30167598,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.30167598,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.30167598,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.30167598,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.30167598,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:15:56 AM","depth":23,"bounds":{"left":0.105053194,"top":0.36073422,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15","depth":24,"bounds":{"left":0.105053194,"top":0.36073422,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща","depth":23,"bounds":{"left":0.11801862,"top":0.35834,"width":0.10172872,"height":0.06703911},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.33359936,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.33359936,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.33359936,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.33359936,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.33359936,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.33359936,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.33359936,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.33359936,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:08 AM","depth":23,"bounds":{"left":0.105053194,"top":0.43735036,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"bounds":{"left":0.105053194,"top":0.43735036,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"без да се съобразява далки е дневен или седмичен или месечен","depth":23,"bounds":{"left":0.11801862,"top":0.4349561,"width":0.09474734,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.4102155,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.4102155,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.4102155,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.4102155,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.4102155,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.4102155,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.4102155,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.4102155,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"bounds":{"left":0.11801862,"top":0.47486034,"width":0.030917553,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14860372,"top":0.4764565,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:16:37 AM","depth":22,"bounds":{"left":0.1512633,"top":0.47885075,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16 AM","depth":23,"bounds":{"left":0.1512633,"top":0.47885075,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"а да, за пращане мисля че няма проверки","depth":23,"bounds":{"left":0.11801862,"top":0.49401435,"width":0.09541223,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.4612929,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.4612929,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.4612929,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.4612929,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.4612929,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.4612929,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.4612929,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.4612929,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:56 AM","depth":23,"bounds":{"left":0.105053194,"top":0.5203512,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"bounds":{"left":0.105053194,"top":0.5203512,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"чакай да видя, мисля че само при генериране","depth":23,"bounds":{"left":0.11801862,"top":0.5179569,"width":0.07712766,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.49321628,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.49321628,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.49321628,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.49321628,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.49321628,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.49321628,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.49321628,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.49321628,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":20,"bounds":{"left":0.21343085,"top":0.547486,"width":0.00930851,"height":0.012769354},"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.11801862,"top":0.55786115,"width":0.038896278,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.15658244,"top":0.5594573,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:18:33 AM","depth":22,"bounds":{"left":0.15924202,"top":0.56185156,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:18 AM","depth":23,"bounds":{"left":0.15924202,"top":0.56185156,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"Иначе ако това е обяснението - нека така си остане.","depth":23,"bounds":{"left":0.11801862,"top":0.57701516,"width":0.10239362,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.5442937,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.5442937,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.5442937,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.5442937,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.5442937,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.5442937,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.5442937,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.5442937,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.118351065,"height":0.030327214},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Adelina Petrova, Direct Message, 1 of 7 suggestions","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.024933511,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova is typing","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.019614361,"height":0.0007980846},"role_description":"text"}]...
|
-666114593636527653
|
-3586248686131838894
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 10:47:31 AM
10:47 AM
сега забелязах че стария count който се ползва в при контрол на достъп canAccessAiReport брои само ресултати който са пратени, не тези които са генерирани
Nikolay Yankov
Yesterday at 1:31:46 PM
1:31 PM
какво значи които са пратени?
Yesterday at 1:32:17 PM
1:32
по принцип условието беше - ако за user-a има генерирано и може да го гледа на ai-reports страницата
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
NULL
|
|
76788
|
NULL
|
0
|
2026-04-24T08:25:07.658513+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019107658_m2.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.796875,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"bounds":{"left":0.8121675,"top":0.019952115,"width":0.103390954,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.63796544,"top":0.12529927,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.6476064,"top":0.123703115,"width":0.00731383,"height":0.018355945},"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.6549202,"top":0.123703115,"width":0.006981383,"height":0.018355945},"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.12210695,"width":0.34375,"height":0.87789303},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Locks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Math, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Playlist, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Prophet, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Queue, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Router, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Saml2, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"SCIM, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Seeder, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sentry, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Serializer, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Settings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Slack, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Transcription, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"role_description":"text"}]...
|
6502072561878735239
|
8404466858121603978
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder...
|
76787
|
|
76789
|
NULL
|
0
|
2026-04-24T08:25:07.755788+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019107755_m1.jpg...
|
PhpStorm
|
faVsco.js – TrackAutomatedReportGeneratedEventTest faVsco.js – TrackAutomatedReportGeneratedEventTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration, folder
Console, folder
Commands, folder
Activities, folder
Analytics, folder
Calendars, folder
Crm, folder
Hubspot, folder
IntegrationApp, folder
Traits, folder
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class
MatchCrmObjectsCommand.php, class
MatchOpportunityActivitiesCommand.php, class
MigrateProvider.php, class
ProcessHubspotObjectsSyncBatches.php, class
PurgeDeletedOpportunitiesCommand.php, class
ResetGovernorLimits.php, class
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TrackAutomatedReportGeneratedEventTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'TrackAutomatedReportGeneratedEventTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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 Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app, folder","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf, folder","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Dtos, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Events, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskAnythingPromptService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"HistoryService.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Locks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Math, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Model, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Notification, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Nudge, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Playlist, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Prophet, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Queue, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Router, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Saml2, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"SCIM, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Seeder, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sentry, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Serializer, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Settings, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Slack, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Transcription, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionSummary, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Twilio, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uploader, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"UrlGenerator, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Utility, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Uuid, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Waveform, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Webhooks, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Workflow, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Configuration, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Console, folder","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Commands, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activities, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Analytics, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Calendars, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Crm, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"Hubspot, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"IntegrationApp, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Traits, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AddLayoutEntities.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AutologDelayedCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornCommandAbstract.php, abstract class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornPingCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSearchCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"BullhornSessionCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CheckActivityLoggableCommand.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CleanDuplicateFieldDataCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"FullSyncOpportunityCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"LogActivitiesCommand.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ManageSyncStrategyCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"MatchCrmObjectsCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"MatchOpportunityActivitiesCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"MigrateProvider.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ProcessHubspotObjectsSyncBatches.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"PurgeDeletedOpportunitiesCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ResetGovernorLimits.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SendNotLogged.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SetupActivityTypeForFollowUp.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SetupCloseCrm.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SetupCopperCrm.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SetupCrmCommand.php, abstract class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayouts.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncAccount.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncContact.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotActiveDeals.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncLead.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesMissingFieldDataCommand.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php, class","depth":11,"role_description":"text"}]...
|
-4130669436458278279
|
8422482356071426818
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
TrackAutomatedReportGeneratedEventTest
Run 'TrackAutomatedReportGeneratedEventTest'
Debug 'TrackAutomatedReportGeneratedEventTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder
FileSystem, folder
Gecko, folder
Gong, folder
GuzzleHttp, folder
KeyPoints, folder
Kiosk, folder
LanguageDetection, folder
LiveFeed, folder
Locks, folder
Math, folder
MediaPipeline, folder
MeetingBot, folder
MobileSettings, folder
Model, folder
Notification, folder
Nudge, folder
ParagraphBreaker, folder
ParticipantSpeech, folder
PartitionedCookie, folder
PlaybackPage, folder
Playlist, folder
Prophet, folder
ProphetAi, folder
ProsperWorks, folder
Queue, folder
Router, folder
Saml2, folder
SCIM, folder
Seeder, folder
Sentry, folder
Serializer, folder
Settings, folder
Sidekick, folder
Slack, folder
TeamInsights, folder
TimeMemoryMapper, folder
Transcription, folder
TranscriptionSummary, folder
Twilio, folder
Uploader, folder
UrlGenerator, folder
Utility, folder
Uuid, folder
Waveform, folder
Webhooks, folder
Workflow, folder
Configuration, folder
Console, folder
Commands, folder
Activities, folder
Analytics, folder
Calendars, folder
Crm, folder
Hubspot, folder
IntegrationApp, folder
Traits, folder
AddLayoutEntities.php, class
AutologDelayedCommand.php, class
BullhornCommandAbstract.php, abstract class
BullhornPingCommand.php, class
BullhornSearchCommand.php, class
BullhornSessionCommand.php, class
CheckActivityLoggableCommand.php, final class
CleanDuplicateFieldDataCommand.php, class
FullSyncOpportunityCommand.php, class
LogActivitiesCommand.php, final class
ManageSyncStrategyCommand.php, class
MatchCrmObjectsCommand.php, class
MatchOpportunityActivitiesCommand.php, class
MigrateProvider.php, class
ProcessHubspotObjectsSyncBatches.php, class
PurgeDeletedOpportunitiesCommand.php, class
ResetGovernorLimits.php, class
SendNotLogged.php, class
SetupActivityTypeForFollowUp.php, final class
SetupCloseCrm.php, class
SetupCopperCrm.php, class
SetupCrmCommand.php, abstract class
SetupLayouts.php, class
SyncAccount.php, class
SyncContact.php, class
SyncFieldMetadata.php, class
SyncHubspotActiveDeals.php, class
SyncHubspotObjects.php, class
SyncLead.php, class
SyncObjects.php, class
SyncOpportunitiesMissingFieldDataCommand.php, class
SyncOpportunity.php, class...
|
76786
|
|
76860
|
NULL
|
0
|
2026-04-24T08:30:26.446802+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019426446_m1.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-9119193263002051277
|
-4836123811583001719
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
76861
|
NULL
|
0
|
2026-04-24T08:30:26.503887+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019426503_m2.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
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.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.14684756,"width":0.2819149,"height":0.8324022},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.96210104,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.98138297,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-9119193263002051277
|
-4836123811583001719
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76858
|
|
76894
|
NULL
|
0
|
2026-04-24T08:35:11.181437+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019711181_m1.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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 Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7887654223188695565
|
-4836126010604164215
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76880
|
|
76895
|
NULL
|
0
|
2026-04-24T08:35:11.388623+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777019711388_m2.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
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.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.5319149,"top":0.19952115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5415558,"top":0.19792499,"width":0.00731383,"height":0.018355945},"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.54886967,"top":0.19792499,"width":0.006981383,"height":0.018355945},"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 Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"bounds":{"left":0.3799867,"top":0.1963288,"width":0.2017952,"height":0.782921},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.74202126,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.75398934,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.7613032,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7887654223188695565
|
-4836126010604164215
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once(); // This seems to be the logic in the controller
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76882
|
|
76914
|
NULL
|
0
|
2026-04-24T08:40:28.790302+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020028790_m1.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"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.0,"top":0.0,"width":0.014583333,"height":0.025555555},"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 Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2226488268323822878
|
-4836126011147322455
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76912
|
|
76915
|
NULL
|
0
|
2026-04-24T08:40:28.942269+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020028942_m2.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
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.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"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.27027926,"top":1.0,"width":0.006981383,"height":0.0},"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 Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"bounds":{"left":0.74202126,"top":0.10055866,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.75398934,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.7613032,"top":0.09896249,"width":0.006981383,"height":0.018355945},"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.24335106,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2226488268323822878
|
-4836126011147322455
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76913
|
|
76933
|
NULL
|
0
|
2026-04-24T08:45:24.486717+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020324486_m1.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"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.0,"top":0.0,"width":0.014583333,"height":0.025555555},"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 Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Http\\Controllers\\Webhook;\n\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Contracts\\Events\\Dispatcher as EventDispatcher;\nuse Illuminate\\Http\\Request;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Http\\Controllers\\Webhook\\ReportController;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsCallbackService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Mockery;\nuse Mockery\\MockInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Tests\\TestCase;\n\nclass ReportControllerTest extends TestCase\n{\n private AutomatedReportsService|MockInterface $reportService;\n private Dispatcher|MockInterface $dispatcher;\n private LoggerInterface|MockInterface $logger;\n private AutomatedReportsCallbackService|MockInterface $callbackService;\n private EventDispatcher|MockInterface $eventDispatcher;\n private ReportController $controller;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n $this->reportService = Mockery::mock(AutomatedReportsService::class);\n $this->dispatcher = Mockery::mock(Dispatcher::class);\n $this->logger = Mockery::mock(LoggerInterface::class);\n $this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);\n $this->eventDispatcher = Mockery::mock(EventDispatcher::class);\n\n $this->logger->shouldReceive('info'); // Allow info logs\n\n $this->controller = new ReportController(\n $this->reportService,\n $this->dispatcher,\n $this->logger,\n $this->callbackService,\n $this->eventDispatcher,\n );\n }\n\n protected function tearDown(): void\n {\n Mockery::close();\n parent::tearDown();\n }\n\n public function testReadyMethodSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn(null);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));\n $this->callbackService->shouldReceive('pushToDatadog')->once();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastSuccess(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n $automatedReport = Mockery::mock(AutomatedReport::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(true);\n\n $reportResult->shouldReceive('getReport')->andReturn($automatedReport);\n $automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);\n $automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->twice();\n $this->callbackService->shouldReceive('pushToDatadog')->twice();\n $this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n\n public function testReadyMethodWithPodcastFailure(): void\n {\n $reportUuid = 'test-uuid';\n $payload = ['request_id' => $reportUuid];\n\n $request = Mockery::mock(Request::class);\n $request->shouldReceive('all')->andReturn($payload);\n\n $reportResult = Mockery::mock(AutomatedReportResult::class);\n $podcastResult = Mockery::mock(AutomatedReportResult::class);\n\n $podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');\n $podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n\n $this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);\n $this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);\n $this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);\n $this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);\n $this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);\n $this->callbackService->shouldReceive('isSuccess')->andReturn(false);\n\n $reportResult->shouldReceive('update')->once();\n $podcastResult->shouldReceive('update')->once();\n $this->dispatcher->shouldReceive('dispatch')->never();\n $this->callbackService->shouldReceive('pushToDatadog')->never();\n\n $this->logger->shouldReceive('warning')->once();\n\n $response = $this->controller->ready($request);\n\n $this->assertEquals(200, $response->getStatusCode());\n $this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"43","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass TrackAutomatedReportGeneratedEvent implements ShouldQueue\n{\n use InteractsWithQueue;\n\n private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';\n private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';\n\n public string $queue = Constants::QUEUE_DELAYABLE;\n\n public function __construct(\n private readonly UserPilotClient $userPilotClient,\n private readonly AutomatedReportsService $automatedReportsService,\n ) {\n }\n\n public function handle(AutomatedReportGenerated $event): void\n {\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n $automatedReport = $event->automatedReport;\n $payload = $this->buildPayload($automatedReport);\n\n $eventName = $this->resolveEventName($automatedReport);\n\n $users = $this->resolveUsers($automatedReport);\n\n if (empty($users)) {\n Log::warning('[UserPilot] No recipients found for automated report', [\n 'report_id' => $automatedReport->getId(),\n 'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),\n ]);\n\n return;\n }\n\n Log::info('[UserPilot] Sending automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'event_name' => $eventName,\n 'recipient_count' => count($users),\n ]);\n\n try {\n foreach ($users as $user) {\n $this->userPilotClient->track($user, $eventName, $payload);\n }\n } catch (GuzzleException $e) {\n Log::error('[UserPilot] Failed to send automated report event', [\n 'report_id' => $automatedReport->getId(),\n 'error' => $e->getMessage(),\n ]);\n $this->release(3600);\n }\n }\n\n /**\n * @return array<UserContract>\n */\n private function resolveUsers(AutomatedReport $automatedReport): array\n {\n if ($automatedReport->isAskJiminnyReport()) {\n $creator = $automatedReport->getCreator();\n\n return $creator !== null ? [$creator] : [];\n }\n\n return $this->automatedReportsService->getRecipientUserObjects($automatedReport);\n }\n\n private function buildPayload(AutomatedReport $automatedReport): array\n {\n return [\n 'report_type' => $automatedReport->getType(),\n 'frequency' => $automatedReport->getFrequency(),\n ];\n }\n\n private function resolveEventName(AutomatedReport $automatedReport): string\n {\n if ($automatedReport->isAskJiminnyReport()) {\n return self::EVENT_NAME_ASK_JIMINNY_REPORT;\n }\n\n return self::EVENT_NAME_AUTOMATED_REPORT;\n }\n}\n\n+++\n\n<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Listeners\\AutomatedReports\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\AutomatedReports\\AutomatedReportGenerated;\nuse Jiminny\\Listeners\\AutomatedReports\\UserPilot\\TrackAutomatedReportGeneratedEvent;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\n\nclass TrackAutomatedReportGeneratedEventTest extends TestCase\n{\n private UserPilotClient&MockObject $userPilotClient;\n private AutomatedReportsService&MockObject $automatedReportsService;\n\n protected function setUp(): void\n {\n parent::setUp();\n $this->userPilotClient = $this->createMock(UserPilotClient::class);\n $this->automatedReportsService = $this->createMock(AutomatedReportsService::class);\n }\n\n private function makeListener(): TrackAutomatedReportGeneratedEvent\n {\n return new TrackAutomatedReportGeneratedEvent(\n $this->userPilotClient,\n $this->automatedReportsService,\n );\n }\n\n private function makeEvent(AutomatedReport $report): AutomatedReportGenerated\n {\n return new AutomatedReportGenerated($report);\n }\n\n public function testHandleSkipsWhenUserPilotTokenIsNull(): void\n {\n config(['services.userpilot.token' => null]);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->never())->method('isAskJiminnyReport');\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksCreatorForAskJiminnyReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn($creator);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(123);\n\n $this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $creator,\n 'ask-jiminny-report-generated',\n ['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);\n $report->expects($this->once())->method('getCreator')->willReturn(null);\n $report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->expects($this->once())->method('getFrequency')->willReturn('weekly');\n $report->expects($this->once())->method('getId')->willReturn(456);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleTracksAllRecipientsForExecReport(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $userOne = $this->createMock(User::class);\n $userTwo = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(789);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$userOne, $userTwo]);\n\n $this->userPilotClient->expects($this->exactly(2))\n ->method('track')\n ->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {\n $this->assertTrue($user === $userOne || $user === $userTwo);\n $this->assertSame('automated-report-generated', $eventName);\n $this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);\n\n return null;\n });\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('exec_summary');\n $report->expects($this->once())->method('getFrequency')->willReturn('monthly');\n $report->expects($this->once())->method('getId')->willReturn(101);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->willReturn([]);\n\n $this->userPilotClient->expects($this->never())->method('track');\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n }\n\n public function testHandleDoesNotThrowOnGuzzleException(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $creator = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('getId')->willReturn(202);\n\n $guzzleException = $this->createMock(GuzzleException::class);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with($creator, 'ask-jiminny-report-generated', $this->anything())\n ->willThrowException($guzzleException);\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\n\n $this->addToAssertionCount(1);\n }\n\n public function testHandleTracksAutomatedReportWithSingleRecipient(): void\n {\n config(['services.userpilot.token' => 'NX-token']);\n\n $user = $this->createMock(User::class);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);\n $report->expects($this->once())->method('getType')->willReturn('team_performance');\n $report->expects($this->once())->method('getFrequency')->willReturn('daily');\n $report->expects($this->once())->method('getId')->willReturn(303);\n\n $this->automatedReportsService->expects($this->once())\n ->method('getRecipientUserObjects')\n ->with($report)\n ->willReturn([$user]);\n\n $this->userPilotClient->expects($this->once())\n ->method('track')\n ->with(\n $user,\n 'automated-report-generated',\n ['report_type' => 'team_performance', 'frequency' => 'daily']\n );\n\n $listener = $this->makeListener();\n $listener->handle($this->makeEvent($report));\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2226488268323822878
|
-4836126011147322455
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Http\Controllers\Webhook;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Illuminate\Http\Request;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Http\Controllers\Webhook\ReportController;
use Jiminny\Jobs\AutomatedReports\SendReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsCallbackService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Mockery;
use Mockery\MockInterface;
use Psr\Log\LoggerInterface;
use Tests\TestCase;
class ReportControllerTest extends TestCase
{
private AutomatedReportsService|MockInterface $reportService;
private Dispatcher|MockInterface $dispatcher;
private LoggerInterface|MockInterface $logger;
private AutomatedReportsCallbackService|MockInterface $callbackService;
private EventDispatcher|MockInterface $eventDispatcher;
private ReportController $controller;
protected function setUp(): void
{
parent::setUp();
$this->reportService = Mockery::mock(AutomatedReportsService::class);
$this->dispatcher = Mockery::mock(Dispatcher::class);
$this->logger = Mockery::mock(LoggerInterface::class);
$this->callbackService = Mockery::mock(AutomatedReportsCallbackService::class);
$this->eventDispatcher = Mockery::mock(EventDispatcher::class);
$this->logger->shouldReceive('info'); // Allow info logs
$this->controller = new ReportController(
$this->reportService,
$this->dispatcher,
$this->logger,
$this->callbackService,
$this->eventDispatcher,
);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
public function testReadyMethodSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn(null);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(SendReportJob::class));
$this->callbackService->shouldReceive('pushToDatadog')->once();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastSuccess(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$automatedReport = Mockery::mock(AutomatedReport::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_GENERATED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(true);
$reportResult->shouldReceive('getReport')->andReturn($automatedReport);
$automatedReport->shouldReceive('getFrequency')->andReturn(AutomatedReportsService::FREQUENCY_ONE_OFF);
$automatedReport->shouldReceive('getUuid')->andReturn('automated-report-uuid');
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->twice();
$this->callbackService->shouldReceive('pushToDatadog')->twice();
$this->eventDispatcher->shouldReceive('dispatch')->once()->with(Mockery::type(AutomatedReportGenerated::class));
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
public function testReadyMethodWithPodcastFailure(): void
{
$reportUuid = 'test-uuid';
$payload = ['request_id' => $reportUuid];
$request = Mockery::mock(Request::class);
$request->shouldReceive('all')->andReturn($payload);
$reportResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult = Mockery::mock(AutomatedReportResult::class);
$podcastResult->shouldReceive('getUuid')->andReturn('podcast-uuid');
$podcastResult->shouldReceive('getStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getResultUuid')->with($payload)->andReturn($reportUuid);
$this->reportService->shouldReceive('getReportResult')->with($reportUuid)->andReturn($reportResult);
$this->callbackService->shouldReceive('isProcessed')->with($reportResult)->andReturn(false);
$this->reportService->shouldReceive('findChildResult')->andReturn($podcastResult);
$this->callbackService->shouldReceive('getPrimaryStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('getPodcastStatus')->andReturn(AutomatedReportResult::STATUS_FAILED);
$this->callbackService->shouldReceive('isSuccess')->andReturn(false);
$reportResult->shouldReceive('update')->once();
$podcastResult->shouldReceive('update')->once();
$this->dispatcher->shouldReceive('dispatch')->never();
$this->callbackService->shouldReceive('pushToDatadog')->never();
$this->logger->shouldReceive('warning')->once();
$response = $this->controller->ready($request);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals(['status' => 'ok'], json_decode($response->getContent(), true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
43
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Jiminny\Component\Queue\Constants;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use Illuminate\Support\Facades\Log;
class TrackAutomatedReportGeneratedEvent implements ShouldQueue
{
use InteractsWithQueue;
private const string EVENT_NAME_AUTOMATED_REPORT = 'automated-report-generated';
private const string EVENT_NAME_ASK_JIMINNY_REPORT = 'ask-jiminny-report-generated';
public string $queue = Constants::QUEUE_DELAYABLE;
public function __construct(
private readonly UserPilotClient $userPilotClient,
private readonly AutomatedReportsService $automatedReportsService,
) {
}
public function handle(AutomatedReportGenerated $event): void
{
if (config('services.userpilot.token') === null) {
return;
}
$automatedReport = $event->automatedReport;
$payload = $this->buildPayload($automatedReport);
$eventName = $this->resolveEventName($automatedReport);
$users = $this->resolveUsers($automatedReport);
if (empty($users)) {
Log::warning('[UserPilot] No recipients found for automated report', [
'report_id' => $automatedReport->getId(),
'is_ask_jiminny' => $automatedReport->isAskJiminnyReport(),
]);
return;
}
Log::info('[UserPilot] Sending automated report event', [
'report_id' => $automatedReport->getId(),
'event_name' => $eventName,
'recipient_count' => count($users),
]);
try {
foreach ($users as $user) {
$this->userPilotClient->track($user, $eventName, $payload);
}
} catch (GuzzleException $e) {
Log::error('[UserPilot] Failed to send automated report event', [
'report_id' => $automatedReport->getId(),
'error' => $e->getMessage(),
]);
$this->release(3600);
}
}
/**
* @return array<UserContract>
*/
private function resolveUsers(AutomatedReport $automatedReport): array
{
if ($automatedReport->isAskJiminnyReport()) {
$creator = $automatedReport->getCreator();
return $creator !== null ? [$creator] : [];
}
return $this->automatedReportsService->getRecipientUserObjects($automatedReport);
}
private function buildPayload(AutomatedReport $automatedReport): array
{
return [
'report_type' => $automatedReport->getType(),
'frequency' => $automatedReport->getFrequency(),
];
}
private function resolveEventName(AutomatedReport $automatedReport): string
{
if ($automatedReport->isAskJiminnyReport()) {
return self::EVENT_NAME_ASK_JIMINNY_REPORT;
}
return self::EVENT_NAME_AUTOMATED_REPORT;
}
}
+++
<?php
declare(strict_types=1);
namespace Tests\Unit\Listeners\AutomatedReports\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\AutomatedReports\AutomatedReportGenerated;
use Jiminny\Listeners\AutomatedReports\UserPilot\TrackAutomatedReportGeneratedEvent;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
class TrackAutomatedReportGeneratedEventTest extends TestCase
{
private UserPilotClient&MockObject $userPilotClient;
private AutomatedReportsService&MockObject $automatedReportsService;
protected function setUp(): void
{
parent::setUp();
$this->userPilotClient = $this->createMock(UserPilotClient::class);
$this->automatedReportsService = $this->createMock(AutomatedReportsService::class);
}
private function makeListener(): TrackAutomatedReportGeneratedEvent
{
return new TrackAutomatedReportGeneratedEvent(
$this->userPilotClient,
$this->automatedReportsService,
);
}
private function makeEvent(AutomatedReport $report): AutomatedReportGenerated
{
return new AutomatedReportGenerated($report);
}
public function testHandleSkipsWhenUserPilotTokenIsNull(): void
{
config(['services.userpilot.token' => null]);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->never())->method('isAskJiminnyReport');
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksCreatorForAskJiminnyReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn($creator);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(123);
$this->automatedReportsService->expects($this->never())->method('getRecipientUserObjects');
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$creator,
'ask-jiminny-report-generated',
['report_type' => AutomatedReportsService::TYPE_ASK_JIMINNY, 'frequency' => 'weekly']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleSkipsTrackingWhenAskJiminnyCreatorIsNull(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(true);
$report->expects($this->once())->method('getCreator')->willReturn(null);
$report->expects($this->once())->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->expects($this->once())->method('getFrequency')->willReturn('weekly');
$report->expects($this->once())->method('getId')->willReturn(456);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleTracksAllRecipientsForExecReport(): void
{
config(['services.userpilot.token' => 'NX-token']);
$userOne = $this->createMock(User::class);
$userTwo = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(789);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$userOne, $userTwo]);
$this->userPilotClient->expects($this->exactly(2))
->method('track')
->willReturnCallback(function ($user, $eventName, $payload) use ($userOne, $userTwo) {
$this->assertTrue($user === $userOne || $user === $userTwo);
$this->assertSame('automated-report-generated', $eventName);
$this->assertSame(['report_type' => 'exec_summary', 'frequency' => 'monthly'], $payload);
return null;
});
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotTrackWhenExecReportHasNoRecipients(): void
{
config(['services.userpilot.token' => 'NX-token']);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(3))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('exec_summary');
$report->expects($this->once())->method('getFrequency')->willReturn('monthly');
$report->expects($this->once())->method('getId')->willReturn(101);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->willReturn([]);
$this->userPilotClient->expects($this->never())->method('track');
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
public function testHandleDoesNotThrowOnGuzzleException(): void
{
config(['services.userpilot.token' => 'NX-token']);
$creator = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->method('isAskJiminnyReport')->willReturn(true);
$report->method('getCreator')->willReturn($creator);
$report->method('getType')->willReturn(AutomatedReportsService::TYPE_ASK_JIMINNY);
$report->method('getFrequency')->willReturn('daily');
$report->method('getId')->willReturn(202);
$guzzleException = $this->createMock(GuzzleException::class);
$this->userPilotClient->expects($this->once())
->method('track')
->with($creator, 'ask-jiminny-report-generated', $this->anything())
->willThrowException($guzzleException);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
$this->addToAssertionCount(1);
}
public function testHandleTracksAutomatedReportWithSingleRecipient(): void
{
config(['services.userpilot.token' => 'NX-token']);
$user = $this->createMock(User::class);
$report = $this->createMock(AutomatedReport::class);
$report->expects($this->exactly(2))->method('isAskJiminnyReport')->willReturn(false);
$report->expects($this->once())->method('getType')->willReturn('team_performance');
$report->expects($this->once())->method('getFrequency')->willReturn('daily');
$report->expects($this->once())->method('getId')->willReturn(303);
$this->automatedReportsService->expects($this->once())
->method('getRecipientUserObjects')
->with($report)
->willReturn([$user]);
$this->userPilotClient->expects($this->once())
->method('track')
->with(
$user,
'automated-report-generated',
['report_type' => 'team_performance', 'frequency' => 'daily']
);
$listener = $this->makeListener();
$listener->handle($this->makeEvent($report));
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
76925
|
|
76934
|
NULL
|
0
|
2026-04-24T08:45:24.373221+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020324373_m2.jpg...
|
PhpStorm
|
faVsco.js – ReportControllerTest.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.25731382,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.29587767,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-817523880274385207
|
-8776372155677736000
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
2
Previous Highlighted Error
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
76913
|
|
77017
|
NULL
|
0
|
2026-04-24T08:50:24.282261+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020624282_m1.jpg...
|
PhpStorm
|
faVsco.js – CreateNudgeCreatedEvent.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Nudges\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Nudges\NudgeCreated;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
use Jiminny\Models\Nudge;
class CreateNudgeCreatedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(NudgeCreated $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
/** @var Nudge $nudge */
$nudge = Nudge::idOrUuId($event->nudgeId);
$this->userPilotService->track(
$nudge->getActivitySearch()->getUser(),
'nudge-created',
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Activities\Coaching\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Activities\Crm\ActivityLogged;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
class CreateActivityLoggedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(ActivityLogged $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
$this->userPilotService->track(
$event->activity->user,
'logged-activity',
$this->generatePayload($event->activity)
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Listeners\\Nudges\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Nudges\\NudgeCreated;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\nuse Jiminny\\Models\\Nudge;\n\nclass CreateNudgeCreatedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(NudgeCreated $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n /** @var Nudge $nudge */\n $nudge = Nudge::idOrUuId($event->nudgeId);\n\n $this->userPilotService->track(\n $nudge->getActivitySearch()->getUser(),\n 'nudge-created',\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Listeners\\Nudges\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Nudges\\NudgeCreated;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\nuse Jiminny\\Models\\Nudge;\n\nclass CreateNudgeCreatedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(NudgeCreated $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n /** @var Nudge $nudge */\n $nudge = Nudge::idOrUuId($event->nudgeId);\n\n $this->userPilotService->track(\n $nudge->getActivitySearch()->getUser(),\n 'nudge-created',\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Listeners\\Activities\\Coaching\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Activities\\Crm\\ActivityLogged;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\n\nclass CreateActivityLoggedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(ActivityLogged $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n $this->userPilotService->track(\n $event->activity->user,\n 'logged-activity',\n $this->generatePayload($event->activity)\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Listeners\\Activities\\Coaching\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Activities\\Crm\\ActivityLogged;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\n\nclass CreateActivityLoggedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(ActivityLogged $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n $this->userPilotService->track(\n $event->activity->user,\n 'logged-activity',\n $this->generatePayload($event->activity)\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8987259266673623237
|
-5264406553245419044
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Nudges\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Nudges\NudgeCreated;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
use Jiminny\Models\Nudge;
class CreateNudgeCreatedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(NudgeCreated $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
/** @var Nudge $nudge */
$nudge = Nudge::idOrUuId($event->nudgeId);
$this->userPilotService->track(
$nudge->getActivitySearch()->getUser(),
'nudge-created',
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Activities\Coaching\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Activities\Crm\ActivityLogged;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
class CreateActivityLoggedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(ActivityLogged $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
$this->userPilotService->track(
$event->activity->user,
'logged-activity',
$this->generatePayload($event->activity)
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
77018
|
NULL
|
0
|
2026-04-24T08:50:24.282272+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020624282_m2.jpg...
|
PhpStorm
|
faVsco.js – CreateNudgeCreatedEvent.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Nudges\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Nudges\NudgeCreated;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
use Jiminny\Models\Nudge;
class CreateNudgeCreatedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(NudgeCreated $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
/** @var Nudge $nudge */
$nudge = Nudge::idOrUuId($event->nudgeId);
$this->userPilotService->track(
$nudge->getActivitySearch()->getUser(),
'nudge-created',
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Activities\Coaching\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Activities\Crm\ActivityLogged;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
class CreateActivityLoggedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(ActivityLogged $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
$this->userPilotService->track(
$event->activity->user,
'logged-activity',
$this->generatePayload($event->activity)
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
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},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.4119016,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.42154256,"top":0.14844373,"width":0.00731383,"height":0.018355945},"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.42885637,"top":0.14844373,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Listeners\\Nudges\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Nudges\\NudgeCreated;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\nuse Jiminny\\Models\\Nudge;\n\nclass CreateNudgeCreatedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(NudgeCreated $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n /** @var Nudge $nudge */\n $nudge = Nudge::idOrUuId($event->nudgeId);\n\n $this->userPilotService->track(\n $nudge->getActivitySearch()->getUser(),\n 'nudge-created',\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","depth":4,"bounds":{"left":0.14594415,"top":0.14684756,"width":0.28989363,"height":0.8324022},"value":"<?php\n\nnamespace Jiminny\\Listeners\\Nudges\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Nudges\\NudgeCreated;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\nuse Jiminny\\Models\\Nudge;\n\nclass CreateNudgeCreatedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(NudgeCreated $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n /** @var Nudge $nudge */\n $nudge = Nudge::idOrUuId($event->nudgeId);\n\n $this->userPilotService->track(\n $nudge->getActivitySearch()->getUser(),\n 'nudge-created',\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7443484,"top":0.10055866,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.75398934,"top":0.09896249,"width":0.00731383,"height":0.018355945},"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.7613032,"top":0.09896249,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Listeners\\Activities\\Coaching\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Activities\\Crm\\ActivityLogged;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\n\nclass CreateActivityLoggedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(ActivityLogged $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n $this->userPilotService->track(\n $event->activity->user,\n 'logged-activity',\n $this->generatePayload($event->activity)\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\n }\n}","depth":4,"bounds":{"left":0.45511967,"top":0.09736632,"width":0.3131649,"height":0.8818835},"value":"<?php\n\nnamespace Jiminny\\Listeners\\Activities\\Coaching\\UserPilot;\n\nuse GuzzleHttp\\Exception\\GuzzleException;\nuse Jiminny\\Events\\Activities\\Crm\\ActivityLogged;\nuse Jiminny\\Listeners\\Activities\\UserPilotActivityListener;\n\nclass CreateActivityLoggedEvent extends UserPilotActivityListener\n{\n /**\n * Handle the event.\n */\n public function handle(ActivityLogged $event): void\n {\n // Don't attempt to run this on environments with UserPilot not configured.\n if (config('services.userpilot.token') === null) {\n return;\n }\n\n try {\n $this->userPilotService->track(\n $event->activity->user,\n 'logged-activity',\n $this->generatePayload($event->activity)\n );\n } catch (GuzzleException $e) {\n // Retry later.\n $this->release(3600);\n }\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,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8987259266673623237
|
-5264406553245419044
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Nudges\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Nudges\NudgeCreated;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
use Jiminny\Models\Nudge;
class CreateNudgeCreatedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(NudgeCreated $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
/** @var Nudge $nudge */
$nudge = Nudge::idOrUuId($event->nudgeId);
$this->userPilotService->track(
$nudge->getActivitySearch()->getUser(),
'nudge-created',
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Listeners\Activities\Coaching\UserPilot;
use GuzzleHttp\Exception\GuzzleException;
use Jiminny\Events\Activities\Crm\ActivityLogged;
use Jiminny\Listeners\Activities\UserPilotActivityListener;
class CreateActivityLoggedEvent extends UserPilotActivityListener
{
/**
* Handle the event.
*/
public function handle(ActivityLogged $event): void
{
// Don't attempt to run this on environments with UserPilot not configured.
if (config('services.userpilot.token') === null) {
return;
}
try {
$this->userPilotService->track(
$event->activity->user,
'logged-activity',
$this->generatePayload($event->activity)
);
} catch (GuzzleException $e) {
// Retry later.
$this->release(3600);
}
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
77016
|
|
77145
|
NULL
|
0
|
2026-04-24T08:56:10.287117+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020970287_m1.jpg...
|
PhpStorm
|
faVsco.js – JiminnyDebugCommand.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
116
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
): void {
// $user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
//
// exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
21
1
17
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
SELECT * FROM automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
SELECT `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01';
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
select * from leads;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"116","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"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;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n ): void {\n // $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n //\n // exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n ): void {\n // $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n //\n // exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\nSELECT `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01';\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;\n\nselect * from leads;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\nSELECT `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01';\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;\n\nselect * from leads;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2103904139782091093
|
1930668812708288077
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
116
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
): void {
// $user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
//
// exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
21
1
17
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
SELECT * FROM automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
SELECT `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01';
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
select * from leads;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
77143
|
|
77146
|
NULL
|
0
|
2026-04-24T08:56:10.287756+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777020970287_m2.jpg...
|
PhpStorm
|
faVsco.js – JiminnyDebugCommand.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
116
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
): void {
// $user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
//
// exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
21
1
17
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
SELECT * FROM automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
SELECT `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01';
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
select * from leads;
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},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.51296544,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"116","depth":4,"bounds":{"left":0.52293885,"top":0.15003991,"width":0.011303191,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.5362367,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.54587764,"top":0.14844373,"width":0.00731383,"height":0.018355945},"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.5531915,"top":0.14844373,"width":0.006981383,"height":0.018355945},"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;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n ): void {\n // $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n //\n // exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n}","depth":4,"bounds":{"left":0.18351063,"top":0.0,"width":0.37666222,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n ): void {\n // $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n //\n // exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.5618351,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.57047874,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.58144945,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.5900931,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.5987367,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.6097075,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.6206782,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.64727396,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.65824467,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.9587766,"top":0.09896249,"width":0.02825798,"height":0.01915403},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.9222075,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.9338431,"top":0.123703115,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.9431516,"top":0.123703115,"width":0.00930851,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.9544548,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.9644282,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.12210695,"width":0.00731383,"height":0.018355945},"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.98138297,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\nSELECT `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01';\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;\n\nselect * from leads;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\nSELECT `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01';\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;\n\nselect * from leads;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2103904139782091093
|
1930668812708288077
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
116
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
): void {
// $user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
//
// exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
21
1
17
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
SELECT * FROM automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
SELECT `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01';
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
select * from leads;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
77144
|
|
77257
|
NULL
|
0
|
2026-04-24T09:01:14.529171+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021274529_m1.jpg...
|
PhpStorm
|
faVsco.js – UserPilotClient.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
3168285612613231679
|
NULL
|
click
|
ocr
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
77255
|
|
77260
|
NULL
|
0
|
2026-04-24T09:01:27.314325+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021287314_m2.jpg...
|
PhpStorm
|
faVsco.js – custom.log
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
115
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
UserPilotClient $userPilotClient
): void {
$user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
$payload = [
'report_type' => 'ask_jiminny',
'frequency' => 'weekly',
];
$userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);
exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
Editor for custom.log
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},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20738-debug-AJ-tracking-UP, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.08510638,"height":0.025538707},"help_text":"Git Branch: JY-20738-debug-AJ-tracking-UP","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.8400931,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"ReportControllerTest","depth":6,"bounds":{"left":0.85538566,"top":0.019952115,"width":0.06017287,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'ReportControllerTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'ReportControllerTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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},"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},"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},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.51296544,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"115","depth":4,"bounds":{"left":0.52293885,"top":0.15003991,"width":0.011303191,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.5362367,"top":0.15003991,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.54587764,"top":0.14844373,"width":0.00731383,"height":0.018355945},"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.5531915,"top":0.14844373,"width":0.006981383,"height":0.018355945},"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;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n UserPilotClient $userPilotClient\n ): void {\n $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n\n $payload = [\n 'report_type' => 'ask_jiminny',\n 'frequency' => 'weekly',\n ];\n $userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);\n\n exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\n }\n}","depth":4,"bounds":{"left":0.18351063,"top":0.0,"width":0.37666222,"height":1.0},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Console\\Commands;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Console\\Command;\nuse InvalidArgumentException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Jobs\\AutomatedReports\\SendReportMailJob;\nuse Jiminny\\Jobs\\JobDispatcherInterface;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Services\\Activity\\CrmOwnerResolver;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\UserPilot\\UserPilotClient;\n\n/**\n * Class JiminnyDebugCommand\n *\n * @package Jiminny\\Console\\Commands\n */\nclass JiminnyDebugCommand extends Command\n{\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n protected $signature = 'jiminny:debug';\n\n public function handle(\n JobDispatcherInterface $jobDispatcher,\n AutomatedReportsService $automatedReportsService,\n AutomatedReportsRepository $automatedReportsRepository,\n UserPilotClient $userPilotClient\n ): void {\n $user = User::find(143);\n // $count = $automatedReportsRepository->countUserReports($user);\n // $this->info(\"Count: {$count}\");\n // $count = $automatedReportsRepository->countAllUserReports($user);\n // $this->info(\"All count: {$count}\");\n\n $payload = [\n 'report_type' => 'ask_jiminny',\n 'frequency' => 'weekly',\n ];\n $userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);\n\n exit(1);\n\n $now = Carbon::now()->subDay(1);\n $this->info(\"Now: {$now->toDateTimeString()}\");\n $weekStart = Carbon::getWeekStartsAt();\n $this->info(\"Now: {$weekStart}\");\n\n // $from = $now->copy()->previousWeekday()->startOfDay();\n // $to = $now->copy()->previousWeekday()->endOfDay();\n\n // $fromOld = $now->copy()->subWeeks(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subWeek()->startOfWeek();\n // $toNew = $now->copy()->subWeek()->endOfWeek();\n\n // $fromOld = $now->copy()->subMonths(1)->startOfDay();\n // $toOld = $now->copy()->subDay()->endOfDay();\n // $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();\n // $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();\n\n $fromOld = $now->copy()->subMonths(3)->startOfDay();\n $toOld = $now->copy()->subDay()->endOfDay();\n $fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();\n $toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();\n\n $this->info(\"From old: {$fromOld->toDateTimeString()}\");\n $this->info(\"To old: {$toOld->toDateTimeString()}\");\n $this->info(\"From new: {$fromNew->toDateTimeString()}\");\n $this->info(\"To new: {$toNew->toDateTimeString()}\");\n\n exit(1);\n\n $report = AutomatedReport::find(71);\n\n $job = new RequestGenerateAskJiminnyReportJob($report->getUuid());\n $jobDispatcher->dispatch($job);\n\n exit(1);\n\n\n // $this->formatDate($jobDispatcher);\n // $this->sendMail($jobDispatcher, $automatedReportsService);\n // $this->crmService();\n\n $this->getPayload($automatedReportsService);\n\n exit(1);\n }\n\n\n\n private function crmService()\n {\n $activity = Activity::find(418141);\n\n $team = Team::find(19);\n $config = $team->getCrmConfiguration();\n\n $crmResolver = app(CrmOwnerResolver::class, [\n 'team' => $team,\n 'integrationAdmin' => $team->getOwner(),\n 'providerSlug' => $config->getProviderName(),\n ]);\n\n $crmService = $crmResolver->prepareCrmService();\n\n $crmService->createTranscriptNotes($activity);\n }\n\n private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)\n {\n $reportUuid = '';\n // $report = $automatedReportsService->getReportResult($reportUuid);\n $report = AutomatedReportResult::find(275);\n $validRecipients = $automatedReportsService->getValidRecipientUsers(\n $report->getReport(),\n includeJiminny: true,\n );\n\n $recipient = $validRecipients[0];\n\n $fileName = $automatedReportsService->getReportFileName($report);\n $typeName = $report->getReport()->getCustomName()\n ?? $automatedReportsService->getReportTypeName($report);\n $teamsName = $automatedReportsService->getReportTeamsName($report);\n $periodName = $automatedReportsService->getReportPeriodName($report);\n $s3Path = $automatedReportsService->getMediaPath($report);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));\n\n $jobDispatcher->dispatch(\n new SendReportMailJob(\n reportUuid: $report->getUuid(),\n s3Path: $s3Path,\n recipientEmail: $recipient['email'],\n recipientName: $recipient['name'] ?? null,\n fileName: $fileName,\n typeName: $typeName,\n teamsName: $teamsName,\n periodName: $periodName,\n isAskJiminny: true,\n )\n );\n\n exit(1);\n }\n\n private function formatDate(JobDispatcherInterface $jobDispatcher): void\n {\n $customName = 'Custom report name';\n // $frequency = self::FREQUENCY_DAILY;\n // $frequency = self::FREQUENCY_WEEKLY;\n $frequency = self::FREQUENCY_MONTHLY;\n // $frequency = self::FREQUENCY_QUARTERLY;\n // $frequency = self::FREQUENCY_ONE_OFF;\n $period = $this->calculateFromAndToDatePeriod($frequency);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n $periodName = $this->formatReportPeriodName($frequency, $from, $to);\n $filenameSuffix = null;\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n $result = $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $this->info($result);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now();\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonths(1)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subMonths(3)->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n private function getPayload(AutomatedReportsService $automatedReportsService)\n {\n $reportResult = AutomatedReportResult::find(269);\n $automatedReport = $reportResult->getReport();\n $activityIds = [1,2,3];\n $payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(\n automatedReport: $automatedReport,\n reportResult: $reportResult,\n activityIds: $activityIds,\n );\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));\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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor for custom.log","depth":4,"bounds":{"left":0.5794548,"top":0.09736632,"width":0.4089096,"height":0.8818835},"role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"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},"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},"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},"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},"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},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
5943993662428371485
|
-5620076461183897717
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20738-debug-AJ-trackin Project: faVsco.js, menu
JY-20738-debug-AJ-tracking-UP, menu
Start Listening for PHP Debug Connections
ReportControllerTest
Run 'ReportControllerTest'
Debug 'ReportControllerTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
115
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Console\Commands;
use Carbon\Carbon;
use Illuminate\Console\Command;
use InvalidArgumentException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Jobs\AutomatedReports\SendReportMailJob;
use Jiminny\Jobs\JobDispatcherInterface;
use Jiminny\Models\Activity;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Services\Activity\CrmOwnerResolver;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\UserPilot\UserPilotClient;
/**
* Class JiminnyDebugCommand
*
* @package Jiminny\Console\Commands
*/
class JiminnyDebugCommand extends Command
{
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
protected $signature = 'jiminny:debug';
public function handle(
JobDispatcherInterface $jobDispatcher,
AutomatedReportsService $automatedReportsService,
AutomatedReportsRepository $automatedReportsRepository,
UserPilotClient $userPilotClient
): void {
$user = User::find(143);
// $count = $automatedReportsRepository->countUserReports($user);
// $this->info("Count: {$count}");
// $count = $automatedReportsRepository->countAllUserReports($user);
// $this->info("All count: {$count}");
$payload = [
'report_type' => 'ask_jiminny',
'frequency' => 'weekly',
];
$userPilotClient->track($user, 'ask-jiminny-report-generated', $payload);
exit(1);
$now = Carbon::now()->subDay(1);
$this->info("Now: {$now->toDateTimeString()}");
$weekStart = Carbon::getWeekStartsAt();
$this->info("Now: {$weekStart}");
// $from = $now->copy()->previousWeekday()->startOfDay();
// $to = $now->copy()->previousWeekday()->endOfDay();
// $fromOld = $now->copy()->subWeeks(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subWeek()->startOfWeek();
// $toNew = $now->copy()->subWeek()->endOfWeek();
// $fromOld = $now->copy()->subMonths(1)->startOfDay();
// $toOld = $now->copy()->subDay()->endOfDay();
// $fromNew = $now->copy()->subMonthNoOverflow()->startOfMonth();
// $toNew = $now->copy()->subMonthNoOverflow()->endOfMonth();
$fromOld = $now->copy()->subMonths(3)->startOfDay();
$toOld = $now->copy()->subDay()->endOfDay();
$fromNew = $now->copy()->subQuarterNoOverflow()->startOfQuarter();
$toNew = $now->copy()->subQuarterNoOverflow()->endOfQuarter();
$this->info("From old: {$fromOld->toDateTimeString()}");
$this->info("To old: {$toOld->toDateTimeString()}");
$this->info("From new: {$fromNew->toDateTimeString()}");
$this->info("To new: {$toNew->toDateTimeString()}");
exit(1);
$report = AutomatedReport::find(71);
$job = new RequestGenerateAskJiminnyReportJob($report->getUuid());
$jobDispatcher->dispatch($job);
exit(1);
// $this->formatDate($jobDispatcher);
// $this->sendMail($jobDispatcher, $automatedReportsService);
// $this->crmService();
$this->getPayload($automatedReportsService);
exit(1);
}
private function crmService()
{
$activity = Activity::find(418141);
$team = Team::find(19);
$config = $team->getCrmConfiguration();
$crmResolver = app(CrmOwnerResolver::class, [
'team' => $team,
'integrationAdmin' => $team->getOwner(),
'providerSlug' => $config->getProviderName(),
]);
$crmService = $crmResolver->prepareCrmService();
$crmService->createTranscriptNotes($activity);
}
private function sendMail(JobDispatcherInterface $jobDispatcher, AutomatedReportsService $automatedReportsService)
{
$reportUuid = '';
// $report = $automatedReportsService->getReportResult($reportUuid);
$report = AutomatedReportResult::find(275);
$validRecipients = $automatedReportsService->getValidRecipientUsers(
$report->getReport(),
includeJiminny: true,
);
$recipient = $validRecipients[0];
$fileName = $automatedReportsService->getReportFileName($report);
$typeName = $report->getReport()->getCustomName()
?? $automatedReportsService->getReportTypeName($report);
$teamsName = $automatedReportsService->getReportTeamsName($report);
$periodName = $automatedReportsService->getReportPeriodName($report);
$s3Path = $automatedReportsService->getMediaPath($report);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$fileName ' . PHP_EOL . print_r($fileName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$typeName ' . PHP_EOL . print_r($typeName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$teamsName ' . PHP_EOL . print_r($teamsName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$periodName ' . PHP_EOL . print_r($periodName, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$s3Path ' . PHP_EOL . print_r($s3Path, true));
$jobDispatcher->dispatch(
new SendReportMailJob(
reportUuid: $report->getUuid(),
s3Path: $s3Path,
recipientEmail: $recipient['email'],
recipientName: $recipient['name'] ?? null,
fileName: $fileName,
typeName: $typeName,
teamsName: $teamsName,
periodName: $periodName,
isAskJiminny: true,
)
);
exit(1);
}
private function formatDate(JobDispatcherInterface $jobDispatcher): void
{
$customName = 'Custom report name';
// $frequency = self::FREQUENCY_DAILY;
// $frequency = self::FREQUENCY_WEEKLY;
$frequency = self::FREQUENCY_MONTHLY;
// $frequency = self::FREQUENCY_QUARTERLY;
// $frequency = self::FREQUENCY_ONE_OFF;
$period = $this->calculateFromAndToDatePeriod($frequency);
$from = $period['fromDate'];
$to = $period['toDate'];
$periodName = $this->formatReportPeriodName($frequency, $from, $to);
$filenameSuffix = null;
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
$result = $this->sanitizeFileName("{$customName} - {$periodName}");
}
$this->info($result);
}
public function calculateFromAndToDatePeriod(
string $frequency,
?Carbon $fromDate = null,
?Carbon $toDate = null
): array {
if ($frequency === self::FREQUENCY_ONE_OFF) {
return [
'fromDate' => $fromDate,
'toDate' => $toDate,
];
}
$now = Carbon::now();
return match ($frequency) {
self::FREQUENCY_DAILY => [
'fromDate' => $now->copy()->subDay()->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_WEEKLY => [
'fromDate' => $now->copy()->subWeeks(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_MONTHLY => [
'fromDate' => $now->copy()->subMonths(1)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
self::FREQUENCY_QUARTERLY => [
'fromDate' => $now->copy()->subMonths(3)->startOfDay(),
'toDate' => $now->copy()->subDay()->endOfDay(),
],
default => throw new InvalidArgumentException("Unsupported frequency: {$frequency}"),
};
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
private function getPayload(AutomatedReportsService $automatedReportsService)
{
$reportResult = AutomatedReportResult::find(269);
$automatedReport = $reportResult->getReport();
$activityIds = [1,2,3];
$payload = $automatedReportsService->getAskJiminnyGenerateReportPayload(
automatedReport: $automatedReport,
reportResult: $reportResult,
activityIds: $activityIds,
);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$payload ' . PHP_EOL . print_r($payload, true));
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
Editor for custom.log
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
77344
|
NULL
|
0
|
2026-04-24T09:06:36.248839+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021596248_m1.jpg...
|
iTerm2
|
-zsh
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Thu Apr 23 14:01:29 on ttys009
Poetry Last login: Thu Apr 23 14:01:29 on ttys009
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23
cd: no such file or directory: 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:31:53] ========================================
[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:31:53] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:32:09] ========================================
[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:32:09] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
NAS mount: OK /Volumes/Test/screenpipe
Archive DB: exists (5.8G)
Data dir: OK (104 files, 165M)
[+00m01s] ▶ Counting source rows for 2026-04-23
frames: 2564
elements: 208937
ui_events: 3546
ocr_text: 904
meetings: 2
[+00m01s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m01s
creating indexes ✓ 0m00s
creating FTS tables ✓ 0m00s
[+00m02s] ▶ Syncing data for 2026-04-23
video_chunks ✓ 0m01s
frames (2564 rows) ✓ 0m27s
ocr_text (904 rows) ✓ 0m14s
ui_events (3546 rows) ✓ 0m01s
elements (208937 rows) ✓ 0m27s
meetings (2 rows) ✓ 0m00s
[+01m12s] ▶ Updating FTS indexes
elements_fts ✓ 0m49s
frames_fts ✓ 1m14s
ui_events_fts ✓ 0m03s
[+03m18s] ▶ Verifying DB
frames: 2564 / 2564 ✓
elements: 208937 / 208937 ✓
ui_events: 3546 / 3546 ✓
ocr_text: 904 / 904 ✓
meetings: 2 / 2 ✓
[+04m31s] ▶ Copying data folder for 2026-04-23
rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)
[2026-04-24 09:36:52] Archive DB size: 6.0G
[2026-04-24 09:36:52] Total time: 4m43s
[2026-04-24 09:36:52] Sync complete for 2026-04-23
[2026-04-24 09:36:52] ========================================
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Thu Apr 23 14:01:29 on ttys009\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23\ncd: no such file or directory: 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:31:53] ========================================\n[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:31:53] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:32:09] ========================================\n[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:32:09] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n NAS mount: OK /Volumes/Test/screenpipe\n Archive DB: exists (5.8G)\n Data dir: OK (104 files, 165M)\n\n[+00m01s] ▶ Counting source rows for 2026-04-23\n frames: 2564\n elements: 208937\n ui_events: 3546\n ocr_text: 904\n meetings: 2\n\n[+00m01s] ▶ Initialising tables, indexes, FTS\n creating tables ✓ 0m01s\n creating indexes ✓ 0m00s\n creating FTS tables ✓ 0m00s\n\n[+00m02s] ▶ Syncing data for 2026-04-23\n video_chunks ✓ 0m01s\n frames (2564 rows) ✓ 0m27s\n ocr_text (904 rows) ✓ 0m14s\n ui_events (3546 rows) ✓ 0m01s\n elements (208937 rows) ✓ 0m27s\n meetings (2 rows) ✓ 0m00s\n\n[+01m12s] ▶ Updating FTS indexes\n elements_fts ✓ 0m49s\n frames_fts ✓ 1m14s\n ui_events_fts ✓ 0m03s\n\n[+03m18s] ▶ Verifying DB\n frames: 2564 / 2564 ✓\n elements: 208937 / 208937 ✓\n ui_events: 3546 / 3546 ✓\n ocr_text: 904 / 904 ✓\n meetings: 2 / 2 ✓\n\n[+04m31s] ▶ Copying data folder for 2026-04-23\n rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)\n\n[2026-04-24 09:36:52] Archive DB size: 6.0G\n[2026-04-24 09:36:52] Total time: 4m43s\n[2026-04-24 09:36:52] Sync complete for 2026-04-23\n[2026-04-24 09:36:52] ========================================\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $","depth":4,"value":"Last login: Thu Apr 23 14:01:29 on ttys009\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23\ncd: no such file or directory: 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:31:53] ========================================\n[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:31:53] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:32:09] ========================================\n[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:32:09] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n NAS mount: OK /Volumes/Test/screenpipe\n Archive DB: exists (5.8G)\n Data dir: OK (104 files, 165M)\n\n[+00m01s] ▶ Counting source rows for 2026-04-23\n frames: 2564\n elements: 208937\n ui_events: 3546\n ocr_text: 904\n meetings: 2\n\n[+00m01s] ▶ Initialising tables, indexes, FTS\n creating tables ✓ 0m01s\n creating indexes ✓ 0m00s\n creating FTS tables ✓ 0m00s\n\n[+00m02s] ▶ Syncing data for 2026-04-23\n video_chunks ✓ 0m01s\n frames (2564 rows) ✓ 0m27s\n ocr_text (904 rows) ✓ 0m14s\n ui_events (3546 rows) ✓ 0m01s\n elements (208937 rows) ✓ 0m27s\n meetings (2 rows) ✓ 0m00s\n\n[+01m12s] ▶ Updating FTS indexes\n elements_fts ✓ 0m49s\n frames_fts ✓ 1m14s\n ui_events_fts ✓ 0m03s\n\n[+03m18s] ▶ Verifying DB\n frames: 2564 / 2564 ✓\n elements: 208937 / 208937 ✓\n ui_events: 3546 / 3546 ✓\n ocr_text: 904 / 904 ✓\n meetings: 2 / 2 ✓\n\n[+04m31s] ▶ Copying data folder for 2026-04-23\n rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)\n\n[2026-04-24 09:36:52] Archive DB size: 6.0G\n[2026-04-24 09:36:52] Total time: 4m43s\n[2026-04-24 09:36:52] Sync complete for 2026-04-23\n[2026-04-24 09:36:52] ========================================\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.0,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.004166667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.16458334,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.16875,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.32916668,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.33333334,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.49340278,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.49756944,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.6576389,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66180557,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.821875,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.82604164,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.95763886,"top":0.032222223,"width":0.03888889,"height":0.018888889},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.48958334,"top":0.033333335,"width":0.022916667,"height":0.017777778},"role_description":"text"}]...
|
2605963857282592989
|
-6889207591244710255
|
click
|
accessibility
|
NULL
|
Last login: Thu Apr 23 14:01:29 on ttys009
Poetry Last login: Thu Apr 23 14:01:29 on ttys009
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23
cd: no such file or directory: 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:31:53] ========================================
[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:31:53] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:32:09] ========================================
[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:32:09] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
NAS mount: OK /Volumes/Test/screenpipe
Archive DB: exists (5.8G)
Data dir: OK (104 files, 165M)
[+00m01s] ▶ Counting source rows for 2026-04-23
frames: 2564
elements: 208937
ui_events: 3546
ocr_text: 904
meetings: 2
[+00m01s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m01s
creating indexes ✓ 0m00s
creating FTS tables ✓ 0m00s
[+00m02s] ▶ Syncing data for 2026-04-23
video_chunks ✓ 0m01s
frames (2564 rows) ✓ 0m27s
ocr_text (904 rows) ✓ 0m14s
ui_events (3546 rows) ✓ 0m01s
elements (208937 rows) ✓ 0m27s
meetings (2 rows) ✓ 0m00s
[+01m12s] ▶ Updating FTS indexes
elements_fts ✓ 0m49s
frames_fts ✓ 1m14s
ui_events_fts ✓ 0m03s
[+03m18s] ▶ Verifying DB
frames: 2564 / 2564 ✓
elements: 208937 / 208937 ✓
ui_events: 3546 / 3546 ✓
ocr_text: 904 / 904 ✓
meetings: 2 / 2 ✓
[+04m31s] ▶ Copying data folder for 2026-04-23
rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)
[2026-04-24 09:36:52] Archive DB size: 6.0G
[2026-04-24 09:36:52] Total time: 4m43s
[2026-04-24 09:36:52] Sync complete for 2026-04-23
[2026-04-24 09:36:52] ========================================
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
NULL
|
|
77345
|
NULL
|
0
|
2026-04-24T09:06:36.248830+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021596248_m2.jpg...
|
iTerm2
|
-zsh
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Thu Apr 23 14:01:29 on ttys009
Poetry Last login: Thu Apr 23 14:01:29 on ttys009
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23
cd: no such file or directory: 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:31:53] ========================================
[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:31:53] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:32:09] ========================================
[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:32:09] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
NAS mount: OK /Volumes/Test/screenpipe
Archive DB: exists (5.8G)
Data dir: OK (104 files, 165M)
[+00m01s] ▶ Counting source rows for 2026-04-23
frames: 2564
elements: 208937
ui_events: 3546
ocr_text: 904
meetings: 2
[+00m01s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m01s
creating indexes ✓ 0m00s
creating FTS tables ✓ 0m00s
[+00m02s] ▶ Syncing data for 2026-04-23
video_chunks ✓ 0m01s
frames (2564 rows) ✓ 0m27s
ocr_text (904 rows) ✓ 0m14s
ui_events (3546 rows) ✓ 0m01s
elements (208937 rows) ✓ 0m27s
meetings (2 rows) ✓ 0m00s
[+01m12s] ▶ Updating FTS indexes
elements_fts ✓ 0m49s
frames_fts ✓ 1m14s
ui_events_fts ✓ 0m03s
[+03m18s] ▶ Verifying DB
frames: 2564 / 2564 ✓
elements: 208937 / 208937 ✓
ui_events: 3546 / 3546 ✓
ocr_text: 904 / 904 ✓
meetings: 2 / 2 ✓
[+04m31s] ▶ Copying data folder for 2026-04-23
rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)
[2026-04-24 09:36:52] Archive DB size: 6.0G
[2026-04-24 09:36:52] Total time: 4m43s
[2026-04-24 09:36:52] Sync complete for 2026-04-23
[2026-04-24 09:36:52] ========================================
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Thu Apr 23 14:01:29 on ttys009\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23\ncd: no such file or directory: 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:31:53] ========================================\n[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:31:53] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:32:09] ========================================\n[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:32:09] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n NAS mount: OK /Volumes/Test/screenpipe\n Archive DB: exists (5.8G)\n Data dir: OK (104 files, 165M)\n\n[+00m01s] ▶ Counting source rows for 2026-04-23\n frames: 2564\n elements: 208937\n ui_events: 3546\n ocr_text: 904\n meetings: 2\n\n[+00m01s] ▶ Initialising tables, indexes, FTS\n creating tables ✓ 0m01s\n creating indexes ✓ 0m00s\n creating FTS tables ✓ 0m00s\n\n[+00m02s] ▶ Syncing data for 2026-04-23\n video_chunks ✓ 0m01s\n frames (2564 rows) ✓ 0m27s\n ocr_text (904 rows) ✓ 0m14s\n ui_events (3546 rows) ✓ 0m01s\n elements (208937 rows) ✓ 0m27s\n meetings (2 rows) ✓ 0m00s\n\n[+01m12s] ▶ Updating FTS indexes\n elements_fts ✓ 0m49s\n frames_fts ✓ 1m14s\n ui_events_fts ✓ 0m03s\n\n[+03m18s] ▶ Verifying DB\n frames: 2564 / 2564 ✓\n elements: 208937 / 208937 ✓\n ui_events: 3546 / 3546 ✓\n ocr_text: 904 / 904 ✓\n meetings: 2 / 2 ✓\n\n[+04m31s] ▶ Copying data folder for 2026-04-23\n rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)\n\n[2026-04-24 09:36:52] Archive DB size: 6.0G\n[2026-04-24 09:36:52] Total time: 4m43s\n[2026-04-24 09:36:52] Sync complete for 2026-04-23\n[2026-04-24 09:36:52] ========================================\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $","depth":4,"value":"Last login: Thu Apr 23 14:01:29 on ttys009\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23\ncd: no such file or directory: 2026-04-23\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll\ntotal 338296\ndrwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .\ndrwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..\n-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg\n-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4\n-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4\n-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4\n-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4\n-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4\n-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4\n-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4\n-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4\n-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4\n-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4\n-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4\n-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4\n-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4\n-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4\n-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4\n-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4\n-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4\n-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4\n-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4\n-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4\n-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4\n-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4\n-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4\n-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4\n-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4\n-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4\n-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4\n-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4\n-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4\n-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4\n-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4\n-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4\n-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4\n-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4\n-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4\n-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4\n-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4\n-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4\n-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4\n-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4\n-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4\n-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4\n-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4\n-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4\n-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4\n-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4\n-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4\n-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4\n-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4\n-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4\n-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4\n-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4\n-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4\n-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4\n-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4\n-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4\n-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4\n-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4\n-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4\n-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4\n-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4\n-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4\n-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4\n-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4\n-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4\n-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4\n-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4\n-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4\n-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4\n-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4\n-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4\n-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4\n-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4\n-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4\n-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4\n-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4\n-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4\n-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4\n-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4\n-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4\n-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4\n-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4\n-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4\n-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4\n-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4\n-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4\n-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4\n-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4\n-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4\n-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4\n-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4\n-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4\n-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4\n-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4\n-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4\n-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4\n-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4\n-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4\n-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4\n-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4\n-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4\n-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4\n-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:31:53] ========================================\n[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:31:53] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23\n[2026-04-24 09:32:09] ========================================\n[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23\n[2026-04-24 09:32:09] ========================================\n\n[+00m00s] ▶ Preflight checks\n Source DB: OK (6.8G)\n NAS mount: OK /Volumes/Test/screenpipe\n Archive DB: exists (5.8G)\n Data dir: OK (104 files, 165M)\n\n[+00m01s] ▶ Counting source rows for 2026-04-23\n frames: 2564\n elements: 208937\n ui_events: 3546\n ocr_text: 904\n meetings: 2\n\n[+00m01s] ▶ Initialising tables, indexes, FTS\n creating tables ✓ 0m01s\n creating indexes ✓ 0m00s\n creating FTS tables ✓ 0m00s\n\n[+00m02s] ▶ Syncing data for 2026-04-23\n video_chunks ✓ 0m01s\n frames (2564 rows) ✓ 0m27s\n ocr_text (904 rows) ✓ 0m14s\n ui_events (3546 rows) ✓ 0m01s\n elements (208937 rows) ✓ 0m27s\n meetings (2 rows) ✓ 0m00s\n\n[+01m12s] ▶ Updating FTS indexes\n elements_fts ✓ 0m49s\n frames_fts ✓ 1m14s\n ui_events_fts ✓ 0m03s\n\n[+03m18s] ▶ Verifying DB\n frames: 2564 / 2564 ✓\n elements: 208937 / 208937 ✓\n ui_events: 3546 / 3546 ✓\n ocr_text: 904 / 904 ✓\n meetings: 2 / 2 ✓\n\n[+04m31s] ▶ Copying data folder for 2026-04-23\n rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)\n\n[2026-04-24 09:36:52] Archive DB size: 6.0G\n[2026-04-24 09:36:52] Total time: 4m43s\n[2026-04-24 09:36:52] Sync complete for 2026-04-23\n[2026-04-24 09:36:52] ========================================\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.27227393,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.34906915,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.35106382,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.42785904,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.42985374,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.5064827,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.5084774,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.5851064,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.58710104,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.66373,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66572475,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.7287234,"top":1.0,"width":0.01861702,"height":-0.023144484},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.5046542,"top":1.0,"width":0.010970744,"height":-0.02394259},"role_description":"text"}]...
|
2605963857282592989
|
-6889207591244710255
|
click
|
accessibility
|
NULL
|
Last login: Thu Apr 23 14:01:29 on ttys009
Poetry Last login: Thu Apr 23 14:01:29 on ttys009
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe/data/data
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ cd 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ cd 2026-04-23
cd: no such file or directory: 2026-04-23
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ll
total 338296
drwxr-xr-x 106 lukas staff 3392 24 Apr 09:20 .
drwxr-xr-x 17 lukas staff 544 24 Apr 09:19 ..
-rw-r--r-- 1 lukas staff 174550 23 Apr 11:38 1776933481776_m1.jpg
-rw-r--r-- 1 lukas staff 1448572 23 Apr 09:24 compact_monitor_1_1776925466477.mp4
-rw-r--r-- 1 lukas staff 2157204 23 Apr 09:29 compact_monitor_1_1776925771961.mp4
-rw-r--r-- 1 lukas staff 785851 23 Apr 09:34 compact_monitor_1_1776926078542.mp4
-rw-r--r-- 1 lukas staff 319924 23 Apr 09:39 compact_monitor_1_1776926389122.mp4
-rw-r--r-- 1 lukas staff 178437 23 Apr 09:44 compact_monitor_1_1776926696343.mp4
-rw-r--r-- 1 lukas staff 182316 23 Apr 09:50 compact_monitor_1_1776927001989.mp4
-rw-r--r-- 1 lukas staff 475405 23 Apr 09:55 compact_monitor_1_1776927311821.mp4
-rw-r--r-- 1 lukas staff 3670216 23 Apr 10:00 compact_monitor_1_1776927616817.mp4
-rw-r--r-- 1 lukas staff 1311845 23 Apr 10:05 compact_monitor_1_1776927930717.mp4
-rw-r--r-- 1 lukas staff 1768745 23 Apr 10:10 compact_monitor_1_1776928242002.mp4
-rw-r--r-- 1 lukas staff 942473 23 Apr 10:15 compact_monitor_1_1776928549085.mp4
-rw-r--r-- 1 lukas staff 911130 23 Apr 10:20 compact_monitor_1_1776928854473.mp4
-rw-r--r-- 1 lukas staff 1249531 23 Apr 10:26 compact_monitor_1_1776929165912.mp4
-rw-r--r-- 1 lukas staff 2106654 23 Apr 10:31 compact_monitor_1_1776929476115.mp4
-rw-r--r-- 1 lukas staff 1633583 23 Apr 10:36 compact_monitor_1_1776929781778.mp4
-rw-r--r-- 1 lukas staff 1186578 23 Apr 10:41 compact_monitor_1_1776930087801.mp4
-rw-r--r-- 1 lukas staff 322993 23 Apr 10:46 compact_monitor_1_1776930392335.mp4
-rw-r--r-- 1 lukas staff 120434 23 Apr 10:51 compact_monitor_1_1776930696294.mp4
-rw-r--r-- 1 lukas staff 111489 23 Apr 10:56 compact_monitor_1_1776931004441.mp4
-rw-r--r-- 1 lukas staff 560588 23 Apr 11:01 compact_monitor_1_1776931314879.mp4
-rw-r--r-- 1 lukas staff 2146373 23 Apr 11:07 compact_monitor_1_1776931618003.mp4
-rw-r--r-- 1 lukas staff 1276021 23 Apr 11:12 compact_monitor_1_1776931930806.mp4
-rw-r--r-- 1 lukas staff 274120 23 Apr 11:17 compact_monitor_1_1776932235717.mp4
-rw-r--r-- 1 lukas staff 212162 23 Apr 11:22 compact_monitor_1_1776932541353.mp4
-rw-r--r-- 1 lukas staff 639071 23 Apr 11:27 compact_monitor_1_1776932847264.mp4
-rw-r--r-- 1 lukas staff 315645 23 Apr 11:32 compact_monitor_1_1776933174068.mp4
-rw-r--r-- 1 lukas staff 518635 23 Apr 11:38 compact_monitor_1_1776933492233.mp4
-rw-r--r-- 1 lukas staff 1886880 23 Apr 11:43 compact_monitor_1_1776933806263.mp4
-rw-r--r-- 1 lukas staff 2316900 23 Apr 11:48 compact_monitor_1_1776934133065.mp4
-rw-r--r-- 1 lukas staff 1589469 23 Apr 11:54 compact_monitor_1_1776934449640.mp4
-rw-r--r-- 1 lukas staff 592352 23 Apr 11:59 compact_monitor_1_1776934755385.mp4
-rw-r--r-- 1 lukas staff 1631938 23 Apr 12:04 compact_monitor_1_1776935058652.mp4
-rw-r--r-- 1 lukas staff 6099603 23 Apr 12:24 compact_monitor_1_1776936289062.mp4
-rw-r--r-- 1 lukas staff 91125 23 Apr 12:35 compact_monitor_1_1776936919782.mp4
-rw-r--r-- 1 lukas staff 2955581 23 Apr 12:40 compact_monitor_1_1776937224602.mp4
-rw-r--r-- 1 lukas staff 3002373 23 Apr 12:45 compact_monitor_1_1776937538337.mp4
-rw-r--r-- 1 lukas staff 3116117 23 Apr 12:50 compact_monitor_1_1776937842939.mp4
-rw-r--r-- 1 lukas staff 2426878 23 Apr 12:55 compact_monitor_1_1776938150380.mp4
-rw-r--r-- 1 lukas staff 2028056 23 Apr 13:01 compact_monitor_1_1776938459676.mp4
-rw-r--r-- 1 lukas staff 2104678 23 Apr 13:06 compact_monitor_1_1776938769006.mp4
-rw-r--r-- 1 lukas staff 3004512 23 Apr 13:11 compact_monitor_1_1776939078771.mp4
-rw-r--r-- 1 lukas staff 1643140 23 Apr 13:16 compact_monitor_1_1776939389326.mp4
-rw-r--r-- 1 lukas staff 1923058 23 Apr 13:21 compact_monitor_1_1776939706398.mp4
-rw-r--r-- 1 lukas staff 900757 23 Apr 13:26 compact_monitor_1_1776940011813.mp4
-rw-r--r-- 1 lukas staff 2964075 23 Apr 13:32 compact_monitor_1_1776940319106.mp4
-rw-r--r-- 1 lukas staff 2419466 23 Apr 13:37 compact_monitor_1_1776940628353.mp4
-rw-r--r-- 1 lukas staff 2447997 23 Apr 13:42 compact_monitor_1_1776940941730.mp4
-rw-r--r-- 1 lukas staff 2202220 23 Apr 13:47 compact_monitor_1_1776941248366.mp4
-rw-r--r-- 1 lukas staff 2309716 23 Apr 13:52 compact_monitor_1_1776941558220.mp4
-rw-r--r-- 1 lukas staff 2049791 23 Apr 13:57 compact_monitor_1_1776941868192.mp4
-rw-r--r-- 1 lukas staff 6097615 24 Apr 09:20 compact_monitor_1_1777011631828.mp4
-rw-r--r-- 1 lukas staff 215938 23 Apr 09:24 compact_monitor_2_1776925467316.mp4
-rw-r--r-- 1 lukas staff 3956084 23 Apr 09:29 compact_monitor_2_1776925774333.mp4
-rw-r--r-- 1 lukas staff 3998164 23 Apr 09:34 compact_monitor_2_1776926081685.mp4
-rw-r--r-- 1 lukas staff 2446471 23 Apr 09:39 compact_monitor_2_1776926391115.mp4
-rw-r--r-- 1 lukas staff 776043 23 Apr 09:44 compact_monitor_2_1776926697217.mp4
-rw-r--r-- 1 lukas staff 802594 23 Apr 09:50 compact_monitor_2_1776927003100.mp4
-rw-r--r-- 1 lukas staff 1453164 23 Apr 09:55 compact_monitor_2_1776927313533.mp4
-rw-r--r-- 1 lukas staff 1449750 23 Apr 10:00 compact_monitor_2_1776927621638.mp4
-rw-r--r-- 1 lukas staff 1635019 23 Apr 10:05 compact_monitor_2_1776927933130.mp4
-rw-r--r-- 1 lukas staff 595843 23 Apr 10:10 compact_monitor_2_1776928245303.mp4
-rw-r--r-- 1 lukas staff 531088 23 Apr 10:15 compact_monitor_2_1776928550520.mp4
-rw-r--r-- 1 lukas staff 846515 23 Apr 10:20 compact_monitor_2_1776928856922.mp4
-rw-r--r-- 1 lukas staff 904088 23 Apr 10:26 compact_monitor_2_1776929169922.mp4
-rw-r--r-- 1 lukas staff 786829 23 Apr 10:31 compact_monitor_2_1776929479675.mp4
-rw-r--r-- 1 lukas staff 729181 23 Apr 10:36 compact_monitor_2_1776929783409.mp4
-rw-r--r-- 1 lukas staff 1116843 23 Apr 10:41 compact_monitor_2_1776930090240.mp4
-rw-r--r-- 1 lukas staff 889822 23 Apr 10:46 compact_monitor_2_1776930393454.mp4
-rw-r--r-- 1 lukas staff 444250 23 Apr 10:51 compact_monitor_2_1776930697139.mp4
-rw-r--r-- 1 lukas staff 1024242 23 Apr 10:56 compact_monitor_2_1776931006436.mp4
-rw-r--r-- 1 lukas staff 1206096 23 Apr 11:01 compact_monitor_2_1776931316182.mp4
-rw-r--r-- 1 lukas staff 1249893 23 Apr 11:07 compact_monitor_2_1776931621999.mp4
-rw-r--r-- 1 lukas staff 401526 23 Apr 11:12 compact_monitor_2_1776931932870.mp4
-rw-r--r-- 1 lukas staff 982256 23 Apr 11:17 compact_monitor_2_1776932236802.mp4
-rw-r--r-- 1 lukas staff 1131582 23 Apr 11:22 compact_monitor_2_1776932542205.mp4
-rw-r--r-- 1 lukas staff 808822 23 Apr 11:27 compact_monitor_2_1776932849317.mp4
-rw-r--r-- 1 lukas staff 442538 23 Apr 11:32 compact_monitor_2_1776933176662.mp4
-rw-r--r-- 1 lukas staff 675274 23 Apr 11:38 compact_monitor_2_1776933495384.mp4
-rw-r--r-- 1 lukas staff 1534516 23 Apr 11:43 compact_monitor_2_1776933812317.mp4
-rw-r--r-- 1 lukas staff 1657590 23 Apr 11:49 compact_monitor_2_1776934138529.mp4
-rw-r--r-- 1 lukas staff 1222887 23 Apr 11:54 compact_monitor_2_1776934453154.mp4
-rw-r--r-- 1 lukas staff 1003999 23 Apr 11:59 compact_monitor_2_1776934756922.mp4
-rw-r--r-- 1 lukas staff 1168918 23 Apr 12:04 compact_monitor_2_1776935062292.mp4
-rw-r--r-- 1 lukas staff 5755378 23 Apr 12:25 compact_monitor_2_1776936297908.mp4
-rw-r--r-- 1 lukas staff 302577 23 Apr 12:25 compact_monitor_2_1776936305094.mp4
-rw-r--r-- 1 lukas staff 1710485 23 Apr 12:35 compact_monitor_2_1776936920837.mp4
-rw-r--r-- 1 lukas staff 2705135 23 Apr 12:40 compact_monitor_2_1776937228721.mp4
-rw-r--r-- 1 lukas staff 1751314 23 Apr 12:45 compact_monitor_2_1776937539934.mp4
-rw-r--r-- 1 lukas staff 924709 23 Apr 12:50 compact_monitor_2_1776937844858.mp4
-rw-r--r-- 1 lukas staff 1285623 23 Apr 12:55 compact_monitor_2_1776938151831.mp4
-rw-r--r-- 1 lukas staff 405857 23 Apr 13:01 compact_monitor_2_1776938461195.mp4
-rw-r--r-- 1 lukas staff 407926 23 Apr 13:06 compact_monitor_2_1776938770290.mp4
-rw-r--r-- 1 lukas staff 958635 23 Apr 13:11 compact_monitor_2_1776939080379.mp4
-rw-r--r-- 1 lukas staff 3622447 23 Apr 13:16 compact_monitor_2_1776939392822.mp4
-rw-r--r-- 1 lukas staff 1850262 23 Apr 13:21 compact_monitor_2_1776939708714.mp4
-rw-r--r-- 1 lukas staff 4725657 23 Apr 13:26 compact_monitor_2_1776940013773.mp4
-rw-r--r-- 1 lukas staff 3590913 23 Apr 13:32 compact_monitor_2_1776940321454.mp4
-rw-r--r-- 1 lukas staff 4073703 23 Apr 13:37 compact_monitor_2_1776940630759.mp4
-rw-r--r-- 1 lukas staff 6432165 23 Apr 13:42 compact_monitor_2_1776940943551.mp4
-rw-r--r-- 1 lukas staff 1484957 23 Apr 13:47 compact_monitor_2_1776941250256.mp4
-rw-r--r-- 1 lukas staff 1336470 23 Apr 13:52 compact_monitor_2_1776941561295.mp4
-rw-r--r-- 1 lukas staff 1327781 23 Apr 13:57 compact_monitor_2_1776941869906.mp4
-rw-r--r-- 1 lukas staff 4219671 24 Apr 09:20 compact_monitor_2_1777011640295.mp4
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:31:53] ========================================
[2026-04-24 09:31:53] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:31:53] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
[2026-04-24 09:31:53] ERROR: NAS not mounted at /Volumes/Test/screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $ ~/.screenpipe/screenpipe_sync.sh 2026-04-23
[2026-04-24 09:32:09] ========================================
[2026-04-24 09:32:09] Screenpipe sync starting for: 2026-04-23
[2026-04-24 09:32:09] ========================================
[+00m00s] ▶ Preflight checks
Source DB: OK (6.8G)
NAS mount: OK /Volumes/Test/screenpipe
Archive DB: exists (5.8G)
Data dir: OK (104 files, 165M)
[+00m01s] ▶ Counting source rows for 2026-04-23
frames: 2564
elements: 208937
ui_events: 3546
ocr_text: 904
meetings: 2
[+00m01s] ▶ Initialising tables, indexes, FTS
creating tables ✓ 0m01s
creating indexes ✓ 0m00s
creating FTS tables ✓ 0m00s
[+00m02s] ▶ Syncing data for 2026-04-23
video_chunks ✓ 0m01s
frames (2564 rows) ✓ 0m27s
ocr_text (904 rows) ✓ 0m14s
ui_events (3546 rows) ✓ 0m01s
elements (208937 rows) ✓ 0m27s
meetings (2 rows) ✓ 0m00s
[+01m12s] ▶ Updating FTS indexes
elements_fts ✓ 0m49s
frames_fts ✓ 1m14s
ui_events_fts ✓ 0m03s
[+03m18s] ▶ Verifying DB
frames: 2564 / 2564 ✓
elements: 208937 / 208937 ✓
ui_events: 3546 / 3546 ✓
ocr_text: 904 / 904 ✓
meetings: 2 / 2 ✓
[+04m31s] ▶ Copying data folder for 2026-04-23
rsync 2026-04-23/ → NAS ✓ 0m12s (104 files, 164M)
[2026-04-24 09:36:52] Archive DB size: 6.0G
[2026-04-24 09:36:52] Total time: 4m43s
[2026-04-24 09:36:52] Sync complete for 2026-04-23
[2026-04-24 09:36:52] ========================================
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data/2026-04-23 $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
NULL
|
|
77397
|
NULL
|
0
|
2026-04-24T09:11:33.717372+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021893717_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
3168285612613231679
|
NULL
|
idle
|
ocr
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
77385
|
|
77398
|
NULL
|
0
|
2026-04-24T09:11:35.980652+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777021895980_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
NULL
|
-8496811010192975640
|
NULL
|
idle
|
ocr
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
77386
|
|
77417
|
NULL
|
0
|
2026-04-24T09:16:37.131751+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022197131_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
3168285612613231679
|
NULL
|
idle
|
ocr
|
NULL
|
Firefox• 0FileEditViewHistory→BookmarksProfilesToo Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
77385
|
|
77418
|
NULL
|
0
|
2026-04-24T09:16:44.295996+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022204295_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
NULL
|
-8496811010192975640
|
NULL
|
idle
|
ocr
|
NULL
|
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJ DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
77386
|
|
77469
|
NULL
|
0
|
2026-04-24T09:21:44.065872+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022504065_m1.jpg...
|
Firefox
|
JY-20738 add debug logs on AJ report UP tracking b JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12013
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
[JY-20738] Debug AJ report User Pilot tracking - J [JY-20738] Debug AJ report User Pilot tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
Close tab
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (30)
Pull requests
(
30
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20738 add debug logs on AJ report UP tracking #12013 Edit title
JY-20738 add debug logs on AJ report UP tracking
#
12013
Edit title
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20738-debug-AJ-tracking-UP
JY-20738-debug-AJ-tracking-UP
Copy head branch name to clipboard
Lines changed: 38 additions & 4 deletions
Conversation (0)
Conversation
(
0
)
Commits (1)
Commits
(
1
)
Checks (2)
Checks
(
2
)
Files changed (4)
Files changed
(
4
)
Conversation
Conversation
@LakyLak
Show options
LakyLak commented now
LakyLak
LakyLak
commented
now
now
JIRA: JY-20738
JIRA:
JY-20738
JY-20738
Changes:
Changes:
Add logs to see why UP events are not registered
Add or remove reactions
@LakyLak
JY-20738
JY-20738
add debug logs on AJ report UP tracking
add debug logs on AJ report UP tracking
9 / 11 checks OK
d7e834d
d7e834d
This branch has not been deployed
This branch has not been deployed
No deployments
Merge info
Merge info
Review required
Review required
At least 1 approving review is required by reviewers with write access.
Some checks haven't completed yet
Some checks haven't completed yet
1 pending, 1 in progress, 1 expected, 9 successful checks
Collapse checks
Collapse 2 pending checks group
2 pending checks
Checks settings
pending checks
pending checks
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
Waiting for status to be reported
— CircleCI is running your tests
More actions
SonarCloud Code Analysis
SonarCloud Code Analysis
Expected
— Waiting for status to be reported
Required
Collapse 1 in progress check group
1 in progress check
in progress checks
in progress checks
Loading
build_accept_deploy
build_accept_deploy
build_accept_deploy
Started
17 minutes ago
— Workflow: build_accept_deploy
More actions
Collapse 9 successful checks group
9 successful checks
successful checks
successful checks
ci/circleci: build-backend
ci/circleci: build-backend
ci/circleci: build-backend
— Your tests passed on CircleCI!
More actions
ci/circleci: build-frontend
ci/circleci: build-frontend
ci/circleci: build-frontend
— Your tests passed on CircleCI!
More actions
ci/circleci: checkout-code
ci/circleci: checkout-code
ci/circleci: checkout-code
— Your tests passed on CircleCI!
More actions
ci/circleci: phpstan
ci/circleci: phpstan
ci/circleci: phpstan
— Your tests passed on CircleCI!
More actions
ci/circleci: setup
ci/circleci: setup
ci/circleci: setup
— Your tests passed on CircleCI!
More actions
ci/circleci: test
ci/circleci: test
ci/circleci: test
— Your tests passed on CircleCI!
More actions
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
— Your tests passed on CircleCI!
More actions
ci/circleci: test-frontend
ci/circleci: test-frontend
ci/circleci: test-frontend
— Your tests passed on CircleCI!
More actions
setup-workflow
setup-workflow
setup-workflow
Successful in 31s
— Workflow: setup-workflow
More actions
This branch is out-of-date with the base branch
This branch is out-of-date with the base branch
Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.
Update branch
Update branch
Update branch options
Merging is blocked
Merging is blocked
At least 1 approving review is required by reviewers with write access.
Enable auto-merge
Enable auto-merge
Select merge method
You can also merge this with the command line.
View command line instructions.
Still in progress?
Convert to draft
Convert to draft
@LakyLak
Add a comment
Add a comment
Comment
Write
Write
Preview
Preview
Comment
Markdown is supported
Markdown
is supported
Paste, drop, or click to add files
Paste, drop, or click to add files
Close pull request
Close pull request
Comment
Remember, contributions to this repository should follow our
GitHub Community Guidelines
GitHub Community Guidelines
.
ProTip!
Add comments to specific lines under
Files changed
Files changed
.
Reviewers
Suggestions
Request
Request
@yalokin-jiminny
yalokin-jiminny
yalokin-jiminny
At least 1 approving review is required to merge this pull request.
Still in progress?
Convert to draft
Assignees
No one—
assign yourself
Labels
None yet
Projects
None yet
Milestone
No milestone
Development
Development
Successfully merging this pull request may close these issues.
None yet
Notifications Customize
Notifications
Customize
Unsubscribe
Unsubscribe
You’re receiving notifications because you’re watching this repository.
1 participant
1 participant
@LakyLak
Lock conversation
Lock conversation
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"[JY-20738] Debug AJ report User Pilot tracking - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.0,"top":0.0,"width":0.022222223,"height":0.035555556},"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.016666668,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (30)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20738 add debug logs on AJ report UP tracking #12013 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20738 add debug logs on AJ report UP tracking","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12013","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Checks pending","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 1 commit into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20738-debug-AJ-tracking-UP","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738-debug-AJ-tracking-UP","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 38 additions & 4 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (0)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (1)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (4)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"LakyLak commented now","depth":14,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"now","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"now","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-20738","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20738","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Changes:","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add logs to see why UP events are not registered","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":17,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"@LakyLak","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20738","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"add debug logs on AJ report UP tracking","depth":14,"help_text":"JY-20738 add debug logs on AJ report UP tracking","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"add debug logs on AJ report UP tracking","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"9 / 11 checks OK","depth":14,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"d7e834d","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"d7e834d","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"This branch has not been deployed","depth":14,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This branch has not been deployed","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No deployments","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Merge info","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge info","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Review required","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Review required","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required by reviewers with write access.","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Some checks haven't completed yet","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Some checks haven't completed yet","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 pending, 1 in progress, 1 expected, 9 successful checks","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse checks","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Collapse 2 pending checks group","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"2 pending checks","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Checks settings","depth":16,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"pending checks","depth":19,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pending checks","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ci/circleci: sonar_cloud","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: sonar_cloud","depth":23,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: sonar_cloud","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Waiting for status to be reported","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— CircleCI is running your tests","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"SonarCloud Code Analysis","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SonarCloud Code Analysis","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expected","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Waiting for status to be reported","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Required","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse 1 in progress check group","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"1 in progress check","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"in progress checks","depth":19,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in progress checks","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Loading","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"build_accept_deploy","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":23,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Started","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 minutes ago","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Workflow: build_accept_deploy","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse 9 successful checks group","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"9 successful checks","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"successful checks","depth":19,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"successful checks","depth":20,"bounds":{"left":0.42708334,"top":0.0,"width":0.10902778,"height":0.09555556},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ci/circleci: build-backend","depth":22,"bounds":{"left":0.47152779,"top":0.0,"width":0.1125,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: build-backend","depth":23,"bounds":{"left":0.47152779,"top":0.0,"width":0.1125,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: build-backend","depth":24,"bounds":{"left":0.47152779,"top":0.0,"width":0.1125,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.5920139,"top":0.0,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: build-frontend","depth":22,"bounds":{"left":0.47152779,"top":0.0,"width":0.11215278,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: build-frontend","depth":23,"bounds":{"left":0.47152779,"top":0.0,"width":0.11215278,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: build-frontend","depth":24,"bounds":{"left":0.47152779,"top":0.0,"width":0.11215278,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.59166664,"top":0.0,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: checkout-code","depth":22,"bounds":{"left":0.47152779,"top":0.0,"width":0.115625,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: checkout-code","depth":23,"bounds":{"left":0.47152779,"top":0.0,"width":0.115625,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: checkout-code","depth":24,"bounds":{"left":0.47152779,"top":0.0,"width":0.115625,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.5951389,"top":0.0,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.0,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: phpstan","depth":22,"bounds":{"left":0.47152779,"top":0.031666666,"width":0.084027775,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: phpstan","depth":23,"bounds":{"left":0.47152779,"top":0.031666666,"width":0.084027775,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: phpstan","depth":24,"bounds":{"left":0.47152779,"top":0.031666666,"width":0.084027775,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.56354165,"top":0.033888888,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.02388889,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: setup","depth":22,"bounds":{"left":0.47152779,"top":0.07277778,"width":0.072916664,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: setup","depth":23,"bounds":{"left":0.47152779,"top":0.07277778,"width":0.072916664,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: setup","depth":24,"bounds":{"left":0.47152779,"top":0.07277778,"width":0.072916664,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.55243057,"top":0.075,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.065,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test","depth":22,"bounds":{"left":0.47152779,"top":0.11388889,"width":0.06493056,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test","depth":23,"bounds":{"left":0.47152779,"top":0.11388889,"width":0.06493056,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test","depth":24,"bounds":{"left":0.47152779,"top":0.11388889,"width":0.06493056,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.54444444,"top":0.116111115,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.10611111,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test-backend-lint","depth":22,"bounds":{"left":0.47152779,"top":0.155,"width":0.12569444,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test-backend-lint","depth":23,"bounds":{"left":0.47152779,"top":0.155,"width":0.12569444,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test-backend-lint","depth":24,"bounds":{"left":0.47152779,"top":0.155,"width":0.12569444,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.60486114,"top":0.15722223,"width":0.12777779,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.14722222,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test-frontend","depth":22,"bounds":{"left":0.47152779,"top":0.19611111,"width":0.10729167,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test-frontend","depth":23,"bounds":{"left":0.47152779,"top":0.19611111,"width":0.10729167,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test-frontend","depth":24,"bounds":{"left":0.47152779,"top":0.19611111,"width":0.10729167,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.5868056,"top":0.19833334,"width":0.12743056,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.18833333,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"setup-workflow","depth":22,"bounds":{"left":0.47152779,"top":0.23722222,"width":0.06979167,"height":0.018888889},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":23,"bounds":{"left":0.47152779,"top":0.23722222,"width":0.06979167,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":24,"bounds":{"left":0.47152779,"top":0.23722222,"width":0.06979167,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Successful in 31s","depth":22,"bounds":{"left":0.546875,"top":0.23944445,"width":0.068055555,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Workflow: setup-workflow","depth":22,"bounds":{"left":0.6170139,"top":0.23944445,"width":0.1125,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.9451389,"top":0.22944444,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"This branch is out-of-date with the base branch","depth":14,"bounds":{"left":0.46041667,"top":0.019444445,"width":0.396875,"height":0.026666667},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This branch is out-of-date with the base branch","depth":15,"bounds":{"left":0.46041667,"top":0.022222223,"width":0.2517361,"height":0.02111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.","depth":15,"bounds":{"left":0.46041667,"top":0.048333332,"width":0.3670139,"height":0.04222222},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update branch","depth":14,"bounds":{"left":0.8628472,"top":0.019444445,"width":0.08645833,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Update branch","depth":16,"bounds":{"left":0.871875,"top":0.027777778,"width":0.068402775,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Update branch options","depth":15,"bounds":{"left":0.94861114,"top":0.019444445,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Merging is blocked","depth":13,"bounds":{"left":0.46041667,"top":0.12944445,"width":0.50972223,"height":0.026666667},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merging is blocked","depth":14,"bounds":{"left":0.46041667,"top":0.13222222,"width":0.099652775,"height":0.02111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required by reviewers with write access.","depth":16,"bounds":{"left":0.46041667,"top":0.15833333,"width":0.3125,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enable auto-merge","depth":12,"bounds":{"left":0.43263888,"top":0.21611111,"width":0.10555556,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enable auto-merge","depth":14,"bounds":{"left":0.44166666,"top":0.22444445,"width":0.0875,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Select merge method","depth":13,"bounds":{"left":0.5375,"top":0.21611111,"width":0.022222223,"height":0.035555556},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"You can also merge this with the command line.","depth":13,"bounds":{"left":0.56458336,"top":0.22555555,"width":0.18680556,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"View command line instructions.","depth":13,"bounds":{"left":0.75381947,"top":0.22388889,"width":0.12708333,"height":0.02},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Still in progress?","depth":13,"bounds":{"left":0.8486111,"top":0.28111112,"width":0.06527778,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Convert to draft","depth":12,"bounds":{"left":0.9166667,"top":0.27944446,"width":0.0625,"height":0.02},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Convert to draft","depth":14,"bounds":{"left":0.9166667,"top":0.28111112,"width":0.0625,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":15,"bounds":{"left":0.38194445,"top":0.3261111,"width":0.027777778,"height":0.044444446},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Add a comment","depth":17,"bounds":{"left":0.42083332,"top":0.3261111,"width":0.08263889,"height":0.026666667},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add a comment","depth":18,"bounds":{"left":0.42083332,"top":0.3288889,"width":0.08263889,"height":0.02111111},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Comment","depth":17,"bounds":{"left":0.42083332,"top":0.3638889,"width":0.04548611,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Write","depth":18,"bounds":{"left":0.42083332,"top":0.36166668,"width":0.047222223,"height":0.044444446},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Write","depth":19,"bounds":{"left":0.43263888,"top":0.375,"width":0.023611112,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Preview","depth":18,"bounds":{"left":0.46805555,"top":0.36166668,"width":0.058680557,"height":0.044444446},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preview","depth":19,"bounds":{"left":0.4798611,"top":0.375,"width":0.035069443,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Comment","depth":20,"bounds":{"left":0.42777777,"top":0.4161111,"width":0.5472222,"height":0.11333334},"placeholder":" ","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Markdown is supported","depth":19,"bounds":{"left":0.42708334,"top":0.53944445,"width":0.12048611,"height":0.031111112},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Markdown","depth":21,"bounds":{"left":0.44722223,"top":0.5466667,"width":0.041319445,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is supported","depth":21,"bounds":{"left":0.48854166,"top":0.5466667,"width":0.05277778,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Paste, drop, or click to add files","depth":18,"bounds":{"left":0.55659723,"top":0.53944445,"width":0.153125,"height":0.031111112},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Paste, drop, or click to add files","depth":20,"bounds":{"left":0.5767361,"top":0.5466667,"width":0.1267361,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close pull request","depth":17,"bounds":{"left":0.7878472,"top":0.58944446,"width":0.12291667,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Close pull request","depth":18,"bounds":{"left":0.81631947,"top":0.5977778,"width":0.08263889,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment","depth":17,"bounds":{"left":0.9135417,"top":0.58944446,"width":0.068402775,"height":0.035555556},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Remember, contributions to this repository should follow our","depth":15,"bounds":{"left":0.43472221,"top":0.63555557,"width":0.23923612,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Community Guidelines","depth":15,"bounds":{"left":0.67395836,"top":0.63555557,"width":0.11805555,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub Community Guidelines","depth":16,"bounds":{"left":0.67395836,"top":0.63555557,"width":0.11805555,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":15,"bounds":{"left":0.7920139,"top":0.63555557,"width":0.0027777778,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProTip!","depth":16,"bounds":{"left":0.571875,"top":0.67388886,"width":0.032986112,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add comments to specific lines under","depth":15,"bounds":{"left":0.60486114,"top":0.67388886,"width":0.17465279,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Files changed","depth":15,"bounds":{"left":0.7795139,"top":0.67388886,"width":0.062152777,"height":0.018888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":16,"bounds":{"left":0.7795139,"top":0.67388886,"width":0.062152777,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":15,"bounds":{"left":0.84166664,"top":0.67388886,"width":0.0027777778,"height":0.018888889},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviewers","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Suggestions","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Request","depth":17,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Request","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@yalokin-jiminny","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"yalokin-jiminny","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required to merge this pull request.","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Still in progress?","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Convert to draft","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Assignees","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"No one—","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"assign yourself","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Labels","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"None yet","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"None yet","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestone","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"No milestone","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Development","depth":17,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Development","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Successfully merging this pull request may close these issues.","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None yet","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications Customize","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Customize","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unsubscribe","depth":16,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unsubscribe","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You’re receiving notifications because you’re watching this repository.","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1 participant","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 participant","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":15,"bounds":{"left":1.0,"top":0.0,"width":-0.0041667223,"height":0.028888889},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Lock conversation","depth":15,"bounds":{"left":1.0,"top":0.0,"width":-0.0041667223,"height":0.02},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lock conversation","depth":17,"bounds":{"left":1.0,"top":0.0,"width":-0.02013886,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer","depth":7,"bounds":{"left":0.09548611,"top":0.74833333,"width":0.00069444446,"height":0.0011111111},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer","depth":8,"bounds":{"left":0.09548611,"top":0.75222224,"width":0.048958335,"height":0.032222223},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Homepage","depth":7,"bounds":{"left":0.49479166,"top":0.74833333,"width":0.016666668,"height":0.028333334},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"© 2026 GitHub, Inc.","depth":8,"bounds":{"left":0.5170139,"top":0.7544444,"width":0.079166666,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer navigation","depth":8,"bounds":{"left":0.6017361,"top":0.75277776,"width":0.00069444446,"height":0.0011111111},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer navigation","depth":9,"bounds":{"left":0.6017361,"top":0.7561111,"width":0.06631944,"height":0.06},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":10,"bounds":{"left":0.60729164,"top":0.7544444,"width":0.023958333,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":11,"bounds":{"left":0.60729164,"top":0.7544444,"width":0.023958333,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":10,"bounds":{"left":0.6423611,"top":0.7544444,"width":0.028819444,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":11,"bounds":{"left":0.6423611,"top":0.7544444,"width":0.028819444,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":10,"bounds":{"left":0.6822917,"top":0.7544444,"width":0.032291666,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":11,"bounds":{"left":0.6822917,"top":0.7544444,"width":0.032291666,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Status","depth":10,"bounds":{"left":0.7256944,"top":0.7544444,"width":0.025347222,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status","depth":11,"bounds":{"left":0.7256944,"top":0.7544444,"width":0.025347222,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":10,"bounds":{"left":0.7621528,"top":0.7544444,"width":0.044444446,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":11,"bounds":{"left":0.7621528,"top":0.7544444,"width":0.044444446,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":10,"bounds":{"left":0.8177083,"top":0.7544444,"width":0.02013889,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":11,"bounds":{"left":0.8177083,"top":0.7544444,"width":0.02013889,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Contact","depth":10,"bounds":{"left":0.8489583,"top":0.7544444,"width":0.03125,"height":0.016666668},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Contact","depth":11,"bounds":{"left":0.8489583,"top":0.7544444,"width":0.03125,"height":0.016666668},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manage cookies","depth":11,"bounds":{"left":0.89131945,"top":0.75277776,"width":0.063541666,"height":0.02},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Do not share my personal information","depth":11,"bounds":{"left":0.96597224,"top":0.75277776,"width":0.034027755,"height":0.02},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
3822900729171176789
|
-5033760803938600756
|
idle
|
accessibility
|
NULL
|
[JY-20738] Debug AJ report User Pilot tracking - J [JY-20738] Debug AJ report User Pilot tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
Close tab
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (30)
Pull requests
(
30
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20738 add debug logs on AJ report UP tracking #12013 Edit title
JY-20738 add debug logs on AJ report UP tracking
#
12013
Edit title
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20738-debug-AJ-tracking-UP
JY-20738-debug-AJ-tracking-UP
Copy head branch name to clipboard
Lines changed: 38 additions & 4 deletions
Conversation (0)
Conversation
(
0
)
Commits (1)
Commits
(
1
)
Checks (2)
Checks
(
2
)
Files changed (4)
Files changed
(
4
)
Conversation
Conversation
@LakyLak
Show options
LakyLak commented now
LakyLak
LakyLak
commented
now
now
JIRA: JY-20738
JIRA:
JY-20738
JY-20738
Changes:
Changes:
Add logs to see why UP events are not registered
Add or remove reactions
@LakyLak
JY-20738
JY-20738
add debug logs on AJ report UP tracking
add debug logs on AJ report UP tracking
9 / 11 checks OK
d7e834d
d7e834d
This branch has not been deployed
This branch has not been deployed
No deployments
Merge info
Merge info
Review required
Review required
At least 1 approving review is required by reviewers with write access.
Some checks haven't completed yet
Some checks haven't completed yet
1 pending, 1 in progress, 1 expected, 9 successful checks
Collapse checks
Collapse 2 pending checks group
2 pending checks
Checks settings
pending checks
pending checks
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
Waiting for status to be reported
— CircleCI is running your tests
More actions
SonarCloud Code Analysis
SonarCloud Code Analysis
Expected
— Waiting for status to be reported
Required
Collapse 1 in progress check group
1 in progress check
in progress checks
in progress checks
Loading
build_accept_deploy
build_accept_deploy
build_accept_deploy
Started
17 minutes ago
— Workflow: build_accept_deploy
More actions
Collapse 9 successful checks group
9 successful checks
successful checks
successful checks
ci/circleci: build-backend
ci/circleci: build-backend
ci/circleci: build-backend
— Your tests passed on CircleCI!
More actions
ci/circleci: build-frontend
ci/circleci: build-frontend
ci/circleci: build-frontend
— Your tests passed on CircleCI!
More actions
ci/circleci: checkout-code
ci/circleci: checkout-code
ci/circleci: checkout-code
— Your tests passed on CircleCI!
More actions
ci/circleci: phpstan
ci/circleci: phpstan
ci/circleci: phpstan
— Your tests passed on CircleCI!
More actions
ci/circleci: setup
ci/circleci: setup
ci/circleci: setup
— Your tests passed on CircleCI!
More actions
ci/circleci: test
ci/circleci: test
ci/circleci: test
— Your tests passed on CircleCI!
More actions
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
— Your tests passed on CircleCI!
More actions
ci/circleci: test-frontend
ci/circleci: test-frontend
ci/circleci: test-frontend
— Your tests passed on CircleCI!
More actions
setup-workflow
setup-workflow
setup-workflow
Successful in 31s
— Workflow: setup-workflow
More actions
This branch is out-of-date with the base branch
This branch is out-of-date with the base branch
Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.
Update branch
Update branch
Update branch options
Merging is blocked
Merging is blocked
At least 1 approving review is required by reviewers with write access.
Enable auto-merge
Enable auto-merge
Select merge method
You can also merge this with the command line.
View command line instructions.
Still in progress?
Convert to draft
Convert to draft
@LakyLak
Add a comment
Add a comment
Comment
Write
Write
Preview
Preview
Comment
Markdown is supported
Markdown
is supported
Paste, drop, or click to add files
Paste, drop, or click to add files
Close pull request
Close pull request
Comment
Remember, contributions to this repository should follow our
GitHub Community Guidelines
GitHub Community Guidelines
.
ProTip!
Add comments to specific lines under
Files changed
Files changed
.
Reviewers
Suggestions
Request
Request
@yalokin-jiminny
yalokin-jiminny
yalokin-jiminny
At least 1 approving review is required to merge this pull request.
Still in progress?
Convert to draft
Assignees
No one—
assign yourself
Labels
None yet
Projects
None yet
Milestone
No milestone
Development
Development
Successfully merging this pull request may close these issues.
None yet
Notifications Customize
Notifications
Customize
Unsubscribe
Unsubscribe
You’re receiving notifications because you’re watching this repository.
1 participant
1 participant
@LakyLak
Lock conversation
Lock conversation
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
NULL
|
|
77470
|
NULL
|
0
|
2026-04-24T09:21:44.166734+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022504166_m2.jpg...
|
Firefox
|
JY-20738 add debug logs on AJ report UP tracking b JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12013
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
[JY-20738] Debug AJ report User Pilot tracking - J [JY-20738] Debug AJ report User Pilot tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
Close tab
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (30)
Pull requests
(
30
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20738 add debug logs on AJ report UP tracking #12013 Edit title
JY-20738 add debug logs on AJ report UP tracking
#
12013
Edit title
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20738-debug-AJ-tracking-UP
JY-20738-debug-AJ-tracking-UP
Copy head branch name to clipboard
Lines changed: 38 additions & 4 deletions
Conversation (0)
Conversation
(
0
)
Commits (1)
Commits
(
1
)
Checks (2)
Checks
(
2
)
Files changed (4)
Files changed
(
4
)
Conversation
Conversation
@LakyLak
Show options
LakyLak commented now
LakyLak
LakyLak
commented
now
now
JIRA: JY-20738
JIRA:
JY-20738
JY-20738
Changes:
Changes:
Add logs to see why UP events are not registered
Add or remove reactions
@LakyLak
JY-20738
JY-20738
add debug logs on AJ report UP tracking
add debug logs on AJ report UP tracking
9 / 11 checks OK
d7e834d
d7e834d
This branch has not been deployed
This branch has not been deployed
No deployments
Merge info
Merge info
Review required
Review required
At least 1 approving review is required by reviewers with write access.
Some checks haven't completed yet
Some checks haven't completed yet
1 pending, 1 in progress, 1 expected, 9 successful checks
Collapse checks
Collapse 2 pending checks group
2 pending checks
Checks settings
pending checks
pending checks
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
Waiting for status to be reported
— CircleCI is running your tests
More actions
SonarCloud Code Analysis
SonarCloud Code Analysis
Expected
— Waiting for status to be reported
Required
Collapse 1 in progress check group
1 in progress check
in progress checks
in progress checks
Loading
build_accept_deploy
build_accept_deploy
build_accept_deploy
Started
17 minutes ago
— Workflow: build_accept_deploy
More actions
Collapse 9 successful checks group
9 successful checks
successful checks
successful checks
ci/circleci: build-backend
ci/circleci: build-backend
ci/circleci: build-backend
— Your tests passed on CircleCI!
More actions
ci/circleci: build-frontend
ci/circleci: build-frontend
ci/circleci: build-frontend
— Your tests passed on CircleCI!
More actions
ci/circleci: checkout-code
ci/circleci: checkout-code
ci/circleci: checkout-code
— Your tests passed on CircleCI!
More actions
ci/circleci: phpstan
ci/circleci: phpstan
ci/circleci: phpstan
— Your tests passed on CircleCI!
More actions
ci/circleci: setup
ci/circleci: setup
ci/circleci: setup
— Your tests passed on CircleCI!
More actions
ci/circleci: test
ci/circleci: test
ci/circleci: test
— Your tests passed on CircleCI!
More actions
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
— Your tests passed on CircleCI!
More actions
ci/circleci: test-frontend
ci/circleci: test-frontend
ci/circleci: test-frontend
— Your tests passed on CircleCI!
More actions
setup-workflow
setup-workflow
setup-workflow
Successful in 31s
— Workflow: setup-workflow
More actions
This branch is out-of-date with the base branch
This branch is out-of-date with the base branch
Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.
Update branch
Update branch
Update branch options
Merging is blocked
Merging is blocked
At least 1 approving review is required by reviewers with write access.
Enable auto-merge
Enable auto-merge
Select merge method
You can also merge this with the command line.
View command line instructions.
Still in progress?
Convert to draft
Convert to draft
@LakyLak
Add a comment
Add a comment
Comment
Write
Write
Preview
Preview
Comment
Markdown is supported
Markdown
is supported
Paste, drop, or click to add files
Paste, drop, or click to add files
Close pull request
Close pull request
Comment
Remember, contributions to this repository should follow our
GitHub Community Guidelines
GitHub Community Guidelines
.
ProTip!
Add comments to specific lines under
Files changed
Files changed
.
Reviewers
Suggestions
Request
Request
@yalokin-jiminny
yalokin-jiminny
yalokin-jiminny
At least 1 approving review is required to merge this pull request.
Still in progress?
Convert to draft
Assignees
No one—
assign yourself
Labels
None yet
Projects
None yet
Milestone
No milestone
Development
Development
Successfully merging this pull request may close these issues.
None yet
Notifications Customize
Notifications
Customize
Unsubscribe
Unsubscribe
You’re receiving notifications because you’re watching this repository.
1 participant
1 participant
@LakyLak
Lock conversation
Lock conversation
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"[JY-20738] Debug AJ report User Pilot tracking - Jira","depth":4,"bounds":{"left":0.23287898,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.10614525,"width":0.1619016,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.23105054,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.2443484,"top":0.13886672,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.17158818,"width":0.14128989,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.20430966,"width":0.17087767,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29837102,"top":0.20031923,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.23703113,"width":0.16356383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.23105054,"top":0.2585794,"width":0.07962101,"height":0.032721467},"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.2443484,"top":0.2697526,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Nudge-created","depth":4,"bounds":{"left":0.23105054,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Nudge-created","depth":5,"bounds":{"left":0.2443484,"top":0.30247405,"width":0.04537899,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Summary - app in Jiminny SonarQube Cloud","depth":4,"bounds":{"left":0.23105054,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summary - app in Jiminny SonarQube Cloud","depth":5,"bounds":{"left":0.2443484,"top":0.33519554,"width":0.07679521,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.23105054,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.2443484,"top":0.367917,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.23387633,"top":0.39106146,"width":0.07413564,"height":0.025538707},"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.23387633,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.24484707,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.25598404,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.26712102,"top":0.97007185,"width":0.010638298,"height":0.025538707},"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.27825797,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"bounds":{"left":0.31067154,"top":0.0518755,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"bounds":{"left":0.31067154,"top":0.05347167,"width":0.0029920214,"height":0.21468475},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"bounds":{"left":0.3159907,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"bounds":{"left":0.33061835,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"bounds":{"left":0.34391624,"top":0.06464485,"width":0.018949468,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"bounds":{"left":0.3459109,"top":0.07063048,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"bounds":{"left":0.3678524,"top":0.06464485,"width":0.017785905,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"bounds":{"left":0.3698471,"top":0.07063048,"width":0.008477394,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"bounds":{"left":0.8166556,"top":0.06464485,"width":0.06565824,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"bounds":{"left":0.8289561,"top":0.07063048,"width":0.011801862,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"bounds":{"left":0.84208775,"top":0.07222666,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"bounds":{"left":0.84607714,"top":0.07063048,"width":0.021276595,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"bounds":{"left":0.8843085,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"bounds":{"left":0.89461434,"top":0.06464485,"width":0.008643617,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"bounds":{"left":0.9112367,"top":0.06464485,"width":0.01662234,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"bounds":{"left":0.9305186,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"bounds":{"left":0.9438165,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"bounds":{"left":0.95711434,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"bounds":{"left":0.97041225,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"bounds":{"left":0.9837101,"top":0.06464485,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"bounds":{"left":0.3103391,"top":0.051077414,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"bounds":{"left":0.3103391,"top":0.05387071,"width":0.0787899,"height":0.023144454},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"bounds":{"left":0.3159907,"top":0.09936153,"width":0.025099734,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"bounds":{"left":0.32679522,"top":0.10574621,"width":0.011469414,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (30)","depth":12,"bounds":{"left":0.34375,"top":0.09936153,"width":0.05518617,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"bounds":{"left":0.3543883,"top":0.10574621,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.3863032,"top":0.113727055,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30","depth":14,"bounds":{"left":0.38929522,"top":0.113727055,"width":0.005817819,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.39511302,"top":0.113727055,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"bounds":{"left":0.40159574,"top":0.09936153,"width":0.029089095,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"bounds":{"left":0.41256648,"top":0.10574621,"width":0.014960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"bounds":{"left":0.43334442,"top":0.09936153,"width":0.03025266,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"bounds":{"left":0.44448137,"top":0.10574621,"width":0.015957447,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"bounds":{"left":0.46625665,"top":0.09936153,"width":0.022938829,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"bounds":{"left":0.47706118,"top":0.10574621,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (1)","depth":12,"bounds":{"left":0.49185506,"top":0.09936153,"width":0.0674867,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"bounds":{"left":0.5036569,"top":0.10574621,"width":0.04255319,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"bounds":{"left":0.5500333,"top":0.113727055,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.55302525,"top":0.113727055,"width":0.0019946808,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"bounds":{"left":0.55502,"top":0.113727055,"width":0.0018284575,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"bounds":{"left":0.56200135,"top":0.09936153,"width":0.031083776,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"bounds":{"left":0.5731383,"top":0.10574621,"width":0.016788565,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.59574467,"top":0.09936153,"width":0.032081116,"height":0.026336791},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.60704786,"top":0.10574621,"width":0.01761968,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"bounds":{"left":0.32430187,"top":0.14365523,"width":0.0003324468,"height":0.016759777},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"bounds":{"left":0.32430187,"top":0.1452514,"width":0.039228722,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"bounds":{"left":0.32430187,"top":0.1452514,"width":0.2159242,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"bounds":{"left":0.54022604,"top":0.1452514,"width":0.04055851,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"bounds":{"left":0.54022604,"top":0.1452514,"width":0.04055851,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"bounds":{"left":0.58078456,"top":0.1452514,"width":0.08261303,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"bounds":{"left":0.6633976,"top":0.1452514,"width":0.05219415,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"bounds":{"left":0.6633976,"top":0.1452514,"width":0.05219415,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"bounds":{"left":0.7155917,"top":0.1452514,"width":0.0013297872,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"bounds":{"left":0.98603725,"top":0.13886672,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20738 add debug logs on AJ report UP tracking #12013 Edit title","depth":13,"bounds":{"left":0.453125,"top":0.19193934,"width":0.28208113,"height":0.031923383},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20738 add debug logs on AJ report UP tracking","depth":14,"bounds":{"left":0.453125,"top":0.19273743,"width":0.23287898,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.68866354,"top":0.19273743,"width":0.006482713,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12013","depth":15,"bounds":{"left":0.69514626,"top":0.19273743,"width":0.028091755,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"bounds":{"left":0.72456783,"top":0.19513169,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Checks pending","depth":13,"bounds":{"left":0.77576464,"top":0.19832402,"width":0.052027926,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"bounds":{"left":0.78806514,"top":0.20430966,"width":0.035405584,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"bounds":{"left":0.82912236,"top":0.19832402,"width":0.02825798,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"bounds":{"left":0.8334442,"top":0.20430966,"width":0.011635638,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"bounds":{"left":0.4637633,"top":0.23623304,"width":0.011968086,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"bounds":{"left":0.48238033,"top":0.2330407,"width":0.018450798,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"bounds":{"left":0.48238033,"top":0.23463687,"width":0.018450798,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 1 commit into","depth":15,"bounds":{"left":0.5021609,"top":0.23463687,"width":0.06349734,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.56698805,"top":0.23264167,"width":0.018284574,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.5689827,"top":0.235834,"width":0.014295213,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.5866024,"top":0.23463687,"width":0.009973404,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20738-debug-AJ-tracking-UP","depth":16,"bounds":{"left":0.5979056,"top":0.23264167,"width":0.07363697,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738-debug-AJ-tracking-UP","depth":17,"bounds":{"left":0.59990025,"top":0.235834,"width":0.0696476,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.67287236,"top":0.23024741,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 38 additions & 4 deletions","depth":14,"bounds":{"left":0.82712764,"top":0.28651237,"width":0.019946808,"height":0.11412609},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (0)","depth":16,"bounds":{"left":0.453125,"top":0.26855546,"width":0.057347074,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"bounds":{"left":0.46675533,"top":0.27813247,"width":0.028091755,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.50482047,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":18,"bounds":{"left":0.5078125,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.51080453,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (1)","depth":16,"bounds":{"left":0.51047206,"top":0.26855546,"width":0.047706116,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"bounds":{"left":0.5241024,"top":0.27813247,"width":0.019115692,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.5525266,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"bounds":{"left":0.5555186,"top":0.27813247,"width":0.0021609042,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.55767953,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"bounds":{"left":0.5581782,"top":0.26855546,"width":0.04504654,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"bounds":{"left":0.5718085,"top":0.27813247,"width":0.015957447,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.59757316,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"bounds":{"left":0.60056514,"top":0.27813247,"width":0.0026595744,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.60322475,"top":0.27813247,"width":0.0018284575,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (4)","depth":16,"bounds":{"left":0.60322475,"top":0.26855546,"width":0.05900931,"height":0.031923383},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"bounds":{"left":0.616855,"top":0.27813247,"width":0.029753989,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.6565825,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":18,"bounds":{"left":0.65957445,"top":0.27813247,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"bounds":{"left":0.6625665,"top":0.27813247,"width":0.0016622341,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation","depth":12,"bounds":{"left":0.453125,"top":0.3140463,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"bounds":{"left":0.453125,"top":0.31683958,"width":0.048204787,"height":0.023144454},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":12,"bounds":{"left":0.453125,"top":0.3140463,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"bounds":{"left":0.72672874,"top":0.31484437,"width":0.007978723,"height":0.02952913},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"LakyLak commented now","depth":14,"bounds":{"left":0.47739363,"top":0.31484437,"width":0.24135639,"height":0.02952913},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":16,"bounds":{"left":0.47739363,"top":0.32282522,"width":0.018450798,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":17,"bounds":{"left":0.47739363,"top":0.32282522,"width":0.018450798,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"bounds":{"left":0.4971742,"top":0.32282522,"width":0.025598405,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"now","depth":15,"bounds":{"left":0.5241024,"top":0.32122904,"width":0.00880984,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"now","depth":17,"bounds":{"left":0.5241024,"top":0.32282522,"width":0.00880984,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-20738","depth":16,"bounds":{"left":0.47739363,"top":0.35794094,"width":0.25731382,"height":0.017557861},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA:","depth":17,"bounds":{"left":0.47739363,"top":0.35834,"width":0.015791224,"height":0.016759777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20738","depth":17,"bounds":{"left":0.49318483,"top":0.35834,"width":0.027260639,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738","depth":18,"bounds":{"left":0.49318483,"top":0.35834,"width":0.027260639,"height":0.016759777},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Changes:","depth":16,"bounds":{"left":0.47739363,"top":0.39465284,"width":0.25731382,"height":0.01396648},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes:","depth":17,"bounds":{"left":0.47739363,"top":0.39465284,"width":0.021110373,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add logs to see why UP events are not registered","depth":18,"bounds":{"left":0.48537233,"top":0.42298484,"width":0.105884306,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":17,"bounds":{"left":0.47739363,"top":0.4509178,"width":0.008643617,"height":0.0207502},"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"@LakyLak","depth":12,"bounds":{"left":0.48537233,"top":0.51476455,"width":0.0066489363,"height":0.015961692},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20738","depth":14,"bounds":{"left":0.49401596,"top":0.51835597,"width":0.019115692,"height":0.011572227},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20738","depth":15,"bounds":{"left":0.49401596,"top":0.51835597,"width":0.019115692,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"add debug logs on AJ report UP tracking","depth":14,"bounds":{"left":0.51545876,"top":0.51835597,"width":0.09358378,"height":0.011572227},"help_text":"JY-20738 add debug logs on AJ report UP tracking","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"add debug logs on AJ report UP tracking","depth":15,"bounds":{"left":0.51545876,"top":0.51835597,"width":0.09358378,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"9 / 11 checks OK","depth":14,"bounds":{"left":0.71675533,"top":0.51476455,"width":0.005319149,"height":0.016759777},"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"d7e834d","depth":14,"bounds":{"left":0.7234042,"top":0.51835597,"width":0.016954787,"height":0.011572227},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"d7e834d","depth":15,"bounds":{"left":0.7234042,"top":0.51835597,"width":0.016954787,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"This branch has not been deployed","depth":14,"bounds":{"left":0.49035904,"top":0.57701516,"width":0.2443484,"height":0.017956903},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This branch has not been deployed","depth":15,"bounds":{"left":0.49035904,"top":0.5786113,"width":0.08843085,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No deployments","depth":14,"bounds":{"left":0.49035904,"top":0.5965682,"width":0.03274601,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Merge info","depth":12,"bounds":{"left":0.47174203,"top":0.63647246,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge info","depth":13,"bounds":{"left":0.47174203,"top":0.6392658,"width":0.023105053,"height":0.0518755},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Review required","depth":13,"bounds":{"left":0.49069148,"top":0.6500399,"width":0.24401596,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Review required","depth":14,"bounds":{"left":0.49069148,"top":0.6520351,"width":0.04055851,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required by reviewers with write access.","depth":14,"bounds":{"left":0.49069148,"top":0.6707901,"width":0.14960106,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Some checks haven't completed yet","depth":13,"bounds":{"left":0.49069148,"top":0.7122905,"width":0.23337767,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Some checks haven't completed yet","depth":14,"bounds":{"left":0.49069148,"top":0.71428573,"width":0.09125665,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 pending, 1 in progress, 1 expected, 9 successful checks","depth":14,"bounds":{"left":0.49069148,"top":0.7330407,"width":0.123171546,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse checks","depth":13,"bounds":{"left":0.47207448,"top":0.6995211,"width":0.2679521,"height":0.061452515},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Collapse 2 pending checks group","depth":16,"bounds":{"left":0.47473404,"top":0.7697526,"width":0.04504654,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"2 pending checks","depth":18,"bounds":{"left":0.47772607,"top":0.77494013,"width":0.03374335,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Checks settings","depth":16,"bounds":{"left":0.72273934,"top":0.7681564,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"pending checks","depth":19,"bounds":{"left":0.47473404,"top":0.79369515,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pending checks","depth":20,"bounds":{"left":0.47473404,"top":0.79768556,"width":0.03939495,"height":0.06863528},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ci/circleci: sonar_cloud","depth":22,"bounds":{"left":0.49601063,"top":0.80087787,"width":0.049035903,"height":0.013567438},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: sonar_cloud","depth":23,"bounds":{"left":0.49601063,"top":0.80087787,"width":0.049035903,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: sonar_cloud","depth":24,"bounds":{"left":0.49601063,"top":0.80087787,"width":0.049035903,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Waiting for status to be reported","depth":22,"bounds":{"left":0.5477061,"top":0.8024741,"width":0.061170213,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— CircleCI is running your tests","depth":22,"bounds":{"left":0.6100399,"top":0.8024741,"width":0.05867686,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":0.7952913,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"SonarCloud Code Analysis","depth":22,"bounds":{"left":0.49601063,"top":0.830407,"width":0.05668218,"height":0.013567438},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SonarCloud Code Analysis","depth":23,"bounds":{"left":0.49601063,"top":0.830407,"width":0.05668218,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expected","depth":22,"bounds":{"left":0.5553524,"top":0.8320032,"width":0.01761968,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Waiting for status to be reported","depth":22,"bounds":{"left":0.57413566,"top":0.8320032,"width":0.06582447,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Required","depth":22,"bounds":{"left":0.70046544,"top":0.8328013,"width":0.017287234,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse 1 in progress check group","depth":16,"bounds":{"left":0.47473404,"top":0.8527534,"width":0.04837101,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"1 in progress check","depth":18,"bounds":{"left":0.47772607,"top":0.8579409,"width":0.03706782,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"in progress checks","depth":19,"bounds":{"left":0.47473404,"top":0.8750998,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in progress checks","depth":20,"bounds":{"left":0.47473404,"top":0.8790902,"width":0.04255319,"height":0.10694334},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Loading","depth":22,"bounds":{"left":0.4793883,"top":0.88467675,"width":0.016954787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"build_accept_deploy","depth":22,"bounds":{"left":0.49601063,"top":0.8822825,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"build_accept_deploy","depth":23,"bounds":{"left":0.49601063,"top":0.8822825,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":24,"bounds":{"left":0.49601063,"top":0.8822825,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Started","depth":22,"bounds":{"left":0.5433843,"top":0.8838787,"width":0.01512633,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 minutes ago","depth":23,"bounds":{"left":0.55851066,"top":0.8838787,"width":0.02825798,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Workflow: build_accept_deploy","depth":22,"bounds":{"left":0.58776593,"top":0.8838787,"width":0.06333112,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":0.87669593,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse 9 successful checks group","depth":16,"bounds":{"left":0.47473404,"top":0.9046289,"width":0.050199468,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"9 successful checks","depth":18,"bounds":{"left":0.47772607,"top":0.90981644,"width":0.038896278,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"successful checks","depth":19,"bounds":{"left":0.47473404,"top":0.92697525,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"successful checks","depth":20,"bounds":{"left":0.47473404,"top":0.93096566,"width":0.05219415,"height":0.06863528},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"ci/circleci: build-backend","depth":22,"bounds":{"left":0.49601063,"top":0.934158,"width":0.053856384,"height":0.013567438},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: build-backend","depth":23,"bounds":{"left":0.49601063,"top":0.934158,"width":0.053856384,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: build-backend","depth":24,"bounds":{"left":0.49601063,"top":0.934158,"width":0.053856384,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.55369014,"top":0.9357542,"width":0.06100399,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":0.9285714,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: build-frontend","depth":22,"bounds":{"left":0.49601063,"top":0.9636871,"width":0.053690158,"height":0.013567438},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: build-frontend","depth":23,"bounds":{"left":0.49601063,"top":0.9636871,"width":0.053690158,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: build-frontend","depth":24,"bounds":{"left":0.49601063,"top":0.9636871,"width":0.053690158,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.55352396,"top":0.96528333,"width":0.06100399,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":0.95810056,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: checkout-code","depth":22,"bounds":{"left":0.49601063,"top":0.9932163,"width":0.055352394,"height":0.006783724},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: checkout-code","depth":23,"bounds":{"left":0.49601063,"top":0.9932163,"width":0.055352394,"height":0.006783724},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: checkout-code","depth":24,"bounds":{"left":0.49601063,"top":0.9932163,"width":0.055352394,"height":0.006783724},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.55518615,"top":0.9948124,"width":0.06100399,"height":0.005187571},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":0.9876297,"width":0.010638298,"height":0.012370288},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: phpstan","depth":22,"bounds":{"left":0.49601063,"top":1.0,"width":0.040226065,"height":-0.02274537},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: phpstan","depth":23,"bounds":{"left":0.49601063,"top":1.0,"width":0.040226065,"height":-0.02274537},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: phpstan","depth":24,"bounds":{"left":0.49601063,"top":1.0,"width":0.040226065,"height":-0.02274537},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.54005986,"top":1.0,"width":0.06100399,"height":-0.024341583},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":1.0,"width":0.010638298,"height":-0.017158866},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: setup","depth":22,"bounds":{"left":0.49601063,"top":1.0,"width":0.034906916,"height":-0.052274585},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: setup","depth":23,"bounds":{"left":0.49601063,"top":1.0,"width":0.034906916,"height":-0.052274585},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: setup","depth":24,"bounds":{"left":0.49601063,"top":1.0,"width":0.034906916,"height":-0.052274585},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.5347407,"top":1.0,"width":0.06100399,"height":-0.053870678},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":1.0,"width":0.010638298,"height":-0.04668796},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test","depth":22,"bounds":{"left":0.49601063,"top":1.0,"width":0.031083776,"height":-0.08180368},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test","depth":23,"bounds":{"left":0.49601063,"top":1.0,"width":0.031083776,"height":-0.08180368},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test","depth":24,"bounds":{"left":0.49601063,"top":1.0,"width":0.031083776,"height":-0.08180368},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"bounds":{"left":0.5309175,"top":1.0,"width":0.06100399,"height":-0.08339989},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"bounds":{"left":0.72273934,"top":1.0,"width":0.010638298,"height":-0.076217055},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test-backend-lint","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test-backend-lint","depth":23,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test-backend-lint","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"ci/circleci: test-frontend","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"ci/circleci: test-frontend","depth":23,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ci/circleci: test-frontend","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Your tests passed on CircleCI!","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"setup-workflow","depth":22,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"setup-workflow","depth":23,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"setup-workflow","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Successful in 31s","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"— Workflow: setup-workflow","depth":22,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions","depth":21,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"This branch is out-of-date with the base branch","depth":14,"bounds":{"left":0.49069148,"top":1.0,"width":0.18999335,"height":-0.013966441},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This branch is out-of-date with the base branch","depth":15,"bounds":{"left":0.49069148,"top":1.0,"width":0.12051197,"height":-0.015961647},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.","depth":15,"bounds":{"left":0.49069148,"top":1.0,"width":0.17569813,"height":-0.034716725},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Update branch","depth":14,"bounds":{"left":0.6833444,"top":1.0,"width":0.04138963,"height":-0.013966441},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Update branch","depth":16,"bounds":{"left":0.68766624,"top":1.0,"width":0.03274601,"height":-0.019952059},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Update branch options","depth":15,"bounds":{"left":0.7244016,"top":1.0,"width":0.010638298,"height":-0.013966441},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Merging is blocked","depth":13,"bounds":{"left":0.49069148,"top":1.0,"width":0.24401596,"height":-0.09297681},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merging is blocked","depth":14,"bounds":{"left":0.49069148,"top":1.0,"width":0.047706116,"height":-0.094972014},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required by reviewers with write access.","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Enable auto-merge","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enable auto-merge","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Select merge method","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"You can also merge this with the command line.","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"View command line instructions.","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Still in progress?","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Convert to draft","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Convert to draft","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Add a comment","depth":17,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add a comment","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Comment","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Write","depth":18,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Write","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Preview","depth":18,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preview","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Comment","depth":20,"placeholder":" ","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Markdown is supported","depth":19,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Markdown","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is supported","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Paste, drop, or click to add files","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Paste, drop, or click to add files","depth":20,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close pull request","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Close pull request","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Remember, contributions to this repository should follow our","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Community Guidelines","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub Community Guidelines","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProTip!","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Add comments to specific lines under","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Files changed","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reviewers","depth":16,"bounds":{"left":0.75099736,"top":0.3140463,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Suggestions","depth":16,"bounds":{"left":0.75099736,"top":0.33918595,"width":0.023271276,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Request","depth":17,"bounds":{"left":0.8415891,"top":0.3603352,"width":0.015791224,"height":0.014365523},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Request","depth":19,"bounds":{"left":0.8415891,"top":0.36153233,"width":0.015791224,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@yalokin-jiminny","depth":16,"bounds":{"left":0.75099736,"top":0.3603352,"width":0.00930851,"height":0.016360734},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"yalokin-jiminny","depth":16,"bounds":{"left":0.7603058,"top":0.3603352,"width":0.029753989,"height":0.016360734},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":17,"bounds":{"left":0.7603058,"top":0.36272946,"width":0.029753989,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"At least 1 approving review is required to merge this pull request.","depth":16,"bounds":{"left":0.75099736,"top":0.3858739,"width":0.105053194,"height":0.026336791},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Still in progress?","depth":16,"bounds":{"left":0.75099736,"top":0.42897046,"width":0.031083776,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Convert to draft","depth":16,"bounds":{"left":0.7834109,"top":0.42777336,"width":0.029920213,"height":0.014365523},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Assignees","depth":16,"bounds":{"left":0.75099736,"top":0.471668,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"No one—","depth":15,"bounds":{"left":0.75099736,"top":0.49680766,"width":0.016788565,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"assign yourself","depth":15,"bounds":{"left":0.7677859,"top":0.49561054,"width":0.02825798,"height":0.014365523},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Labels","depth":15,"bounds":{"left":0.75099736,"top":0.5331205,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"None yet","depth":14,"bounds":{"left":0.75099736,"top":0.5582602,"width":0.016788565,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Projects","depth":16,"bounds":{"left":0.75099736,"top":0.594573,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"None yet","depth":15,"bounds":{"left":0.75099736,"top":0.6197127,"width":0.016788565,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Milestone","depth":16,"bounds":{"left":0.75099736,"top":0.6560255,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"No milestone","depth":15,"bounds":{"left":0.75099736,"top":0.6811652,"width":0.024601065,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Development","depth":17,"bounds":{"left":0.75099736,"top":0.7206704,"width":0.10638298,"height":0.014365523},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Development","depth":18,"bounds":{"left":0.75099736,"top":0.7218675,"width":0.025764627,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Successfully merging this pull request may close these issues.","depth":18,"bounds":{"left":0.75099736,"top":0.7426177,"width":0.10305851,"height":0.026336791},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None yet","depth":18,"bounds":{"left":0.75099736,"top":0.7793296,"width":0.016788565,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications Customize","depth":15,"bounds":{"left":0.75099736,"top":0.8156425,"width":0.10638298,"height":0.0207502},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":17,"bounds":{"left":0.75099736,"top":0.82003194,"width":0.025099734,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Customize","depth":17,"bounds":{"left":0.8374335,"top":0.82003194,"width":0.019946808,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unsubscribe","depth":16,"bounds":{"left":0.75099736,"top":0.839585,"width":0.10638298,"height":0.022346368},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unsubscribe","depth":18,"bounds":{"left":0.795379,"top":0.8447725,"width":0.024102394,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You’re receiving notifications because you’re watching this repository.","depth":16,"bounds":{"left":0.75099736,"top":0.86632085,"width":0.1022274,"height":0.026336791},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1 participant","depth":15,"bounds":{"left":0.75099736,"top":0.9201915,"width":0.10638298,"height":0.014365523},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1 participant","depth":16,"bounds":{"left":0.75099736,"top":0.9213887,"width":0.02443484,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":15,"bounds":{"left":0.75099736,"top":0.94413406,"width":0.008643617,"height":0.0207502},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Lock conversation","depth":15,"bounds":{"left":0.75099736,"top":0.9912211,"width":0.04338431,"height":0.00877893},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lock conversation","depth":17,"bounds":{"left":0.7586436,"top":0.99241817,"width":0.035738032,"height":0.00758183},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer","depth":7,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer","depth":8,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub Homepage","depth":7,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"© 2026 GitHub, Inc.","depth":8,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Footer navigation","depth":8,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Footer navigation","depth":9,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Terms","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Terms","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Privacy","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Privacy","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Status","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Status","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Community","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Community","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Docs","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Docs","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Contact","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Contact","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Manage cookies","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Do not share my personal information","depth":11,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
3822900729171176789
|
-5033760803938600756
|
idle
|
accessibility
|
NULL
|
[JY-20738] Debug AJ report User Pilot tracking - J [JY-20738] Debug AJ report User Pilot tracking - Jira
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
JY-20489 | Optimize Nudges - Phase 2 by yalokin-jiminny · Pull Request #11997 · jiminny/app
New Tab
New Tab
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
AI reports promotion pages by nikolay-yankov · Pull Request #11998 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
JY-20738 add debug logs on AJ report UP tracking by LakyLak · Pull Request #12013 · jiminny/app
Close tab
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
JY-20157 add not enough activities notification by LakyLak · Pull Request #12011 · jiminny/app
Jiminny
Jiminny
Userpilot | Nudge-created
Userpilot | Nudge-created
Summary - app in Jiminny SonarQube Cloud
Summary - app in Jiminny SonarQube Cloud
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (30)
Pull requests
(
30
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (1)
Security and quality
(
1
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20738 add debug logs on AJ report UP tracking #12013 Edit title
JY-20738 add debug logs on AJ report UP tracking
#
12013
Edit title
Checks pending
Checks pending
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20738-debug-AJ-tracking-UP
JY-20738-debug-AJ-tracking-UP
Copy head branch name to clipboard
Lines changed: 38 additions & 4 deletions
Conversation (0)
Conversation
(
0
)
Commits (1)
Commits
(
1
)
Checks (2)
Checks
(
2
)
Files changed (4)
Files changed
(
4
)
Conversation
Conversation
@LakyLak
Show options
LakyLak commented now
LakyLak
LakyLak
commented
now
now
JIRA: JY-20738
JIRA:
JY-20738
JY-20738
Changes:
Changes:
Add logs to see why UP events are not registered
Add or remove reactions
@LakyLak
JY-20738
JY-20738
add debug logs on AJ report UP tracking
add debug logs on AJ report UP tracking
9 / 11 checks OK
d7e834d
d7e834d
This branch has not been deployed
This branch has not been deployed
No deployments
Merge info
Merge info
Review required
Review required
At least 1 approving review is required by reviewers with write access.
Some checks haven't completed yet
Some checks haven't completed yet
1 pending, 1 in progress, 1 expected, 9 successful checks
Collapse checks
Collapse 2 pending checks group
2 pending checks
Checks settings
pending checks
pending checks
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
ci/circleci: sonar_cloud
Waiting for status to be reported
— CircleCI is running your tests
More actions
SonarCloud Code Analysis
SonarCloud Code Analysis
Expected
— Waiting for status to be reported
Required
Collapse 1 in progress check group
1 in progress check
in progress checks
in progress checks
Loading
build_accept_deploy
build_accept_deploy
build_accept_deploy
Started
17 minutes ago
— Workflow: build_accept_deploy
More actions
Collapse 9 successful checks group
9 successful checks
successful checks
successful checks
ci/circleci: build-backend
ci/circleci: build-backend
ci/circleci: build-backend
— Your tests passed on CircleCI!
More actions
ci/circleci: build-frontend
ci/circleci: build-frontend
ci/circleci: build-frontend
— Your tests passed on CircleCI!
More actions
ci/circleci: checkout-code
ci/circleci: checkout-code
ci/circleci: checkout-code
— Your tests passed on CircleCI!
More actions
ci/circleci: phpstan
ci/circleci: phpstan
ci/circleci: phpstan
— Your tests passed on CircleCI!
More actions
ci/circleci: setup
ci/circleci: setup
ci/circleci: setup
— Your tests passed on CircleCI!
More actions
ci/circleci: test
ci/circleci: test
ci/circleci: test
— Your tests passed on CircleCI!
More actions
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
ci/circleci: test-backend-lint
— Your tests passed on CircleCI!
More actions
ci/circleci: test-frontend
ci/circleci: test-frontend
ci/circleci: test-frontend
— Your tests passed on CircleCI!
More actions
setup-workflow
setup-workflow
setup-workflow
Successful in 31s
— Workflow: setup-workflow
More actions
This branch is out-of-date with the base branch
This branch is out-of-date with the base branch
Merge the latest changes from master into this branch. This merge commit will be associated with LakyLak.
Update branch
Update branch
Update branch options
Merging is blocked
Merging is blocked
At least 1 approving review is required by reviewers with write access.
Enable auto-merge
Enable auto-merge
Select merge method
You can also merge this with the command line.
View command line instructions.
Still in progress?
Convert to draft
Convert to draft
@LakyLak
Add a comment
Add a comment
Comment
Write
Write
Preview
Preview
Comment
Markdown is supported
Markdown
is supported
Paste, drop, or click to add files
Paste, drop, or click to add files
Close pull request
Close pull request
Comment
Remember, contributions to this repository should follow our
GitHub Community Guidelines
GitHub Community Guidelines
.
ProTip!
Add comments to specific lines under
Files changed
Files changed
.
Reviewers
Suggestions
Request
Request
@yalokin-jiminny
yalokin-jiminny
yalokin-jiminny
At least 1 approving review is required to merge this pull request.
Still in progress?
Convert to draft
Assignees
No one—
assign yourself
Labels
None yet
Projects
None yet
Milestone
No milestone
Development
Development
Successfully merging this pull request may close these issues.
None yet
Notifications Customize
Notifications
Customize
Unsubscribe
Unsubscribe
You’re receiving notifications because you’re watching this repository.
1 participant
1 participant
@LakyLak
Lock conversation
Lock conversation
Footer
Footer
GitHub Homepage
© 2026 GitHub, Inc.
Footer navigation
Footer navigation
Terms
Terms
Privacy
Privacy
Security
Security
Status
Status
Community
Community
Docs
Docs
Contact
Contact
Manage cookies
Do not share my personal information...
|
NULL
|
|
77502
|
NULL
|
0
|
2026-04-24T09:27:04.562538+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022824562_m1.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - Slack...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:20:59 AM
11:20 AM
да send cron job събира неизпратени ресултати
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:21:55 AM
11:21
и преценява само по timezone на recipients кога да го прати но в рамките на същия ден
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:23:35 AM
11:23
просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:24:11 AM
11:24 AM
oki
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:25:06 AM
11:25
ок е това
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:35:32 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:35 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:13:41 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:05 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"седмични не са ли в понеделник само","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:19 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:56 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:08 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"без да се съобразява далки е дневен или седмичен или месечен","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:16:37 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"а да, за пращане мисля че няма проверки","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:56 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"чакай да видя, мисля че само при генериране","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:18:33 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:18 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Иначе ако това е обяснението - нека така си остане.","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:20:59 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:20 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да send cron job събира неизпратени ресултати","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:21:55 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:21","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"и преценява само по timezone на recipients кога да го прати но в рамките на същия ден","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:23:35 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:23","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":20,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:24:11 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:24 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"oki","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:25:06 AM","depth":23,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:25","depth":24,"role_description":"text"},{"role":"AXStaticText","text":"ок е това","depth":23,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Adelina Petrova, Direct Message, 1 of 7 suggestions","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova is typing","depth":11,"role_description":"text"}]...
|
-379473194515243256
|
-1568636053069840302
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:20:59 AM
11:20 AM
да send cron job събира неизпратени ресултати
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:21:55 AM
11:21
и преценява само по timezone на recipients кога да го прати но в рамките на същия ден
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:23:35 AM
11:23
просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:24:11 AM
11:24 AM
oki
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:25:06 AM
11:25
ок е това
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing
Firefox• 0FileEditViewHistory→BookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.com•Daily - Platform - now100% K78 • Fri 24 Apr 9:46:13|=Pop out this videoNikolay NikolovStefka StoyanovaGalya DimitrovaLukas Kovalik9:46 AM | Daily - Platform• 0:27...
|
NULL
|
|
77503
|
NULL
|
0
|
2026-04-24T09:27:04.619934+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-24/1777 /Users/lukas/.screenpipe/data/data/2026-04-24/1777022824619_m2.jpg...
|
Slack
|
Aneliya Angelova, Nikolay Yankov, Steliyan Georgie Aneliya Angelova, Nikolay Yankov, Steliyan Georgiev (DM) - Jiminny Inc - Slack...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:20:59 AM
11:20 AM
да send cron job събира неизпратени ресултати
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:21:55 AM
11:21
и преценява само по timezone на recipients кога да го прати но в рамките на същия ден
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:23:35 AM
11:23
просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:24:11 AM
11:24 AM
oki
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:25:06 AM
11:25
ок е това
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.0056515955,"top":0.058260176,"width":0.011968086,"height":0.028731046},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"bounds":{"left":0.0029920214,"top":0.10055866,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"bounds":{"left":0.0066489363,"top":0.13806863,"width":0.009973404,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"bounds":{"left":0.0029920214,"top":0.15482841,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"bounds":{"left":0.0076462766,"top":0.19233839,"width":0.007978723,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"bounds":{"left":0.0029920214,"top":0.20909816,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"bounds":{"left":0.004986702,"top":0.24660814,"width":0.012965426,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"bounds":{"left":0.0029920214,"top":0.26336792,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"bounds":{"left":0.0076462766,"top":0.3008779,"width":0.0076462766,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"bounds":{"left":0.0029920214,"top":0.31763768,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"bounds":{"left":0.00731383,"top":0.35514766,"width":0.008643617,"height":0.0103751},"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"bounds":{"left":0.0029920214,"top":0.3719074,"width":0.017287234,"height":0.054269753},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"bounds":{"left":0.006981383,"top":0.4094174,"width":0.008976064,"height":0.0103751},"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.042220745,"top":0.10853951,"width":0.043882977,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":24,"bounds":{"left":0.042220745,"top":0.13088587,"width":0.045877658,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.042220745,"top":0.18355946,"width":0.022273935,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"ai-team","depth":23,"bounds":{"left":0.042220745,"top":0.20590582,"width":0.01662234,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.042220745,"top":0.22825219,"width":0.011968086,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.042220745,"top":0.25059855,"width":0.018284574,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"c-learning-people","depth":23,"bounds":{"left":0.042220745,"top":0.27294493,"width":0.038231384,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.042220745,"top":0.2952913,"width":0.034242023,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"bounds":{"left":0.042220745,"top":0.31763768,"width":0.027593086,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"deal-insights-dev","depth":23,"bounds":{"left":0.042220745,"top":0.33998403,"width":0.03723404,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"bounds":{"left":0.042220745,"top":0.3623304,"width":0.025598405,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"frontend","depth":23,"bounds":{"left":0.042220745,"top":0.38467678,"width":0.018949468,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"bounds":{"left":0.042220745,"top":0.40702313,"width":0.015957447,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"infra-changes","depth":23,"bounds":{"left":0.042220745,"top":0.4293695,"width":0.029587766,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"bounds":{"left":0.042220745,"top":0.4517159,"width":0.022938829,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-copilot-licences","depth":23,"bounds":{"left":0.042220745,"top":0.47406226,"width":0.045212764,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"people-with-zoom-phone-licences","depth":23,"bounds":{"left":0.042220745,"top":0.4964086,"width":0.045877658,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-team","depth":23,"bounds":{"left":0.042220745,"top":0.51875496,"width":0.03125,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"bounds":{"left":0.042220745,"top":0.54110134,"width":0.034906916,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"bounds":{"left":0.042220745,"top":0.5634477,"width":0.03856383,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"bounds":{"left":0.042220745,"top":0.5857941,"width":0.01662234,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"bounds":{"left":0.042220745,"top":0.60814047,"width":0.018284574,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"bounds":{"left":0.042220745,"top":0.63048685,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"bounds":{"left":0.042220745,"top":0.6528332,"width":0.016954787,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"bounds":{"left":0.042220745,"top":0.67517954,"width":0.024268618,"height":0.014365523},"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"bounds":{"left":0.042220745,"top":0.6975259,"width":0.04488032,"height":0.011971269},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.07945479,"top":0.7086991,"width":0.0063164895,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.08211436,"top":0.7086991,"width":0.014295213,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"bounds":{"left":0.09607713,"top":0.7086991,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"bounds":{"left":0.09607713,"top":0.7086991,"width":0.0003324468,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Adelina Petrova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.026263298,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tomov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.030585106,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034906916,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.032912236,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03756649,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Mario Georgiev","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.033909574,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Todor Stamatov","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.034242023,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.03523936,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.021609042,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"bounds":{"left":0.042220745,"top":0.7086991,"width":0.011635638,"height":0.0007980846},"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.10206117,"top":0.09177973,"width":0.030585106,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"bounds":{"left":0.111369684,"top":0.10055866,"width":0.01861702,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"bounds":{"left":0.13397606,"top":0.09177973,"width":0.033909574,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"bounds":{"left":0.14328457,"top":0.10055866,"width":0.021941489,"height":0.012769354},"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.16921543,"top":0.09177973,"width":0.020944148,"height":0.030327214},"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"bounds":{"left":0.17852394,"top":0.10055866,"width":0.008976064,"height":0.012769354},"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.19115691,"top":0.09177973,"width":0.010970744,"height":0.030327214},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.015625,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.0076462766,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"bounds":{"left":0.096409574,"top":0.0518755,"width":0.013962766,"height":0.0007980846},"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Yesterday at 1:35:32 PM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1:35 PM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":21,"bounds":{"left":0.15026596,"top":0.12689546,"width":0.025265958,"height":0.022346368},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:13:41 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:13 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.","depth":23,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:05 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"седмични не са ли в понеделник само","depth":23,"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:19 AM","depth":22,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15 AM","depth":23,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":23,"bounds":{"left":0.11801862,"top":0.11572227,"width":0.0056515955,"height":0.007980846},"role_description":"text"},{"role":"AXLink","text":"Today at 11:15:56 AM","depth":23,"bounds":{"left":0.105053194,"top":0.13567439,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:15","depth":24,"bounds":{"left":0.105053194,"top":0.13567439,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща","depth":23,"bounds":{"left":0.11801862,"top":0.13328013,"width":0.10172872,"height":0.06703911},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.11572227,"width":0.010638298,"height":0.018355945},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.11572227,"width":0.010638298,"height":0.018355945},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.11572227,"width":0.010638298,"height":0.018355945},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.11572227,"width":0.010638298,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.11572227,"width":0.010638298,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.11572227,"width":0.0003324468,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.11572227,"width":0.0003324468,"height":0.018355945},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.11572227,"width":0.0003324468,"height":0.018355945},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:08 AM","depth":23,"bounds":{"left":0.105053194,"top":0.2122905,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"bounds":{"left":0.105053194,"top":0.2122905,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"без да се съобразява далки е дневен или седмичен или месечен","depth":23,"bounds":{"left":0.11801862,"top":0.20989625,"width":0.09474734,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.18515563,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.18515563,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.18515563,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.18515563,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.18515563,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.18515563,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.18515563,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.18515563,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"bounds":{"left":0.11801862,"top":0.24980047,"width":0.030917553,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14860372,"top":0.25139666,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:16:37 AM","depth":22,"bounds":{"left":0.1512633,"top":0.25379092,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16 AM","depth":23,"bounds":{"left":0.1512633,"top":0.25379092,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"а да, за пращане мисля че няма проверки","depth":23,"bounds":{"left":0.11801862,"top":0.26895452,"width":0.09541223,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.23623304,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.23623304,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.23623304,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.23623304,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.23623304,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.23623304,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.23623304,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.23623304,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:16:56 AM","depth":23,"bounds":{"left":0.105053194,"top":0.2952913,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:16","depth":24,"bounds":{"left":0.105053194,"top":0.2952913,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"чакай да видя, мисля че само при генериране","depth":23,"bounds":{"left":0.11801862,"top":0.29289705,"width":0.07712766,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.26815644,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.26815644,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.26815644,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.26815644,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.26815644,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.26815644,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.26815644,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.26815644,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.11801862,"top":0.33280128,"width":0.038896278,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.15658244,"top":0.33439744,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:18:33 AM","depth":22,"bounds":{"left":0.15924202,"top":0.3367917,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:18 AM","depth":23,"bounds":{"left":0.15924202,"top":0.3367917,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"Иначе ако това е обяснението - нека така си остане.","depth":23,"bounds":{"left":0.11801862,"top":0.3519553,"width":0.10239362,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.31923383,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.31923383,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.31923383,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.31923383,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.31923383,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.31923383,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.31923383,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.31923383,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":22,"bounds":{"left":0.11801862,"top":0.39185953,"width":0.030917553,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.14860372,"top":0.3934557,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:20:59 AM","depth":22,"bounds":{"left":0.1512633,"top":0.39584997,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:20 AM","depth":23,"bounds":{"left":0.1512633,"top":0.39584997,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"да send cron job събира неизпратени ресултати","depth":23,"bounds":{"left":0.11801862,"top":0.41101357,"width":0.08444149,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.3782921,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.3782921,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.3782921,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.3782921,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.3782921,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.3782921,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.3782921,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.3782921,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:21:55 AM","depth":23,"bounds":{"left":0.105053194,"top":0.45490822,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:21","depth":24,"bounds":{"left":0.105053194,"top":0.45490822,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"и преценява само по timezone на recipients кога да го прати но в рамките на същия ден","depth":23,"bounds":{"left":0.11801862,"top":0.45251396,"width":0.10106383,"height":0.031923383},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.42777336,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.42777336,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.42777336,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.42777336,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.42777336,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.42777336,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.42777336,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.42777336,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:23:35 AM","depth":23,"bounds":{"left":0.105053194,"top":0.4964086,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:23","depth":24,"bounds":{"left":0.105053194,"top":0.4964086,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job","depth":23,"bounds":{"left":0.11801862,"top":0.49401435,"width":0.10239362,"height":0.049481247},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.46927375,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.46927375,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.46927375,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.46927375,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.46927375,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.46927375,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.46927375,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.46927375,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New","depth":20,"bounds":{"left":0.21343085,"top":0.54110134,"width":0.00930851,"height":0.012769354},"role_description":"text"},{"role":"AXButton","text":"Aneliya Angelova","depth":22,"bounds":{"left":0.11801862,"top":0.5514765,"width":0.038896278,"height":0.017557861},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.15658244,"top":0.55307263,"width":0.0029920214,"height":0.014365523},"role_description":"text"},{"role":"AXLink","text":"Today at 11:24:11 AM","depth":22,"bounds":{"left":0.15924202,"top":0.5554669,"width":0.01761968,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:24 AM","depth":23,"bounds":{"left":0.15924202,"top":0.5554669,"width":0.01761968,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"oki","depth":23,"bounds":{"left":0.11801862,"top":0.5706305,"width":0.0066489363,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.53790903,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.53790903,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.53790903,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.53790903,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.53790903,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.53790903,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.53790903,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.53790903,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:25:06 AM","depth":23,"bounds":{"left":0.105053194,"top":0.5969673,"width":0.010305851,"height":0.011173184},"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:25","depth":24,"bounds":{"left":0.105053194,"top":0.5969673,"width":0.010305851,"height":0.011173184},"role_description":"text"},{"role":"AXStaticText","text":"ок е това","depth":23,"bounds":{"left":0.11801862,"top":0.594573,"width":0.020944148,"height":0.014365523},"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":24,"bounds":{"left":0.13730054,"top":0.5698324,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":24,"bounds":{"left":0.14793883,"top":0.5698324,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":24,"bounds":{"left":0.15857713,"top":0.5698324,"width":0.010638298,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":24,"bounds":{"left":0.16921543,"top":0.5698324,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":24,"bounds":{"left":0.17985372,"top":0.5698324,"width":0.010638298,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":24,"bounds":{"left":0.22340426,"top":0.5698324,"width":0.0003324468,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":24,"bounds":{"left":0.22340426,"top":0.5698324,"width":0.0003324468,"height":0.025538707},"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":24,"bounds":{"left":0.22340426,"top":0.5698324,"width":0.0003324468,"height":0.025538707},"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":23,"bounds":{"left":0.10372341,"top":0.6272945,"width":0.118351065,"height":0.030327214},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Adelina Petrova, Direct Message, 1 of 7 suggestions","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.024933511,"height":0.0007980846},"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova is typing","depth":11,"bounds":{"left":0.0,"top":0.7126895,"width":0.019614361,"height":0.0007980846},"role_description":"text"}]...
|
-379473194515243256
|
-1568636053069840302
|
click
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
ai-team
alerts
backend
c-learning-people
confusion-clinic
curiosity_lab
deal-insights-dev
engineering
frontend
general
infra-changes
jiminny-bg
people-with-copilot-licences
people-with-zoom-phone-licences
platform-team
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stefka Stoyanova
Adelina Petrova
Vasil Vasilev
Stoyan Tomov
Galya Dimitrova
Nikolay Yankov
Petko Kashinski
Aneliya Angelova
Nikolay Nikolov
Mario Georgiev
Todor Stamatov
Gabriela Dureva
Jira Cloud
Toast
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Lukas Kovalik
Yesterday at 1:35:32 PM
1:35 PM
да, говоря за нещо още от преди, count който се гледа дали има user право да гледа ai-reports страница , брои пратени не тези който са генерирани само. Реално ако се праща всичко на ред почти няма да се вижда разлика
(edited)
Jump to date
Aneliya Angelova
Today at 11:13:41 AM
11:13 AM
Лукаш вчера генерирах 3 седмични репорта на. Галя на prod us. Обаче не ги пуснах по емейл и тази сутрин ги е получила по мейл.
Lukas Kovalik
Today at 11:15:05 AM
11:15 AM
седмични не са ли в понеделник само
Aneliya Angelova
Today at 11:15:19 AM
11:15 AM
да
Today at 11:15:56 AM
11:15
аз ги генерирах вчера. Да не би сутрин да минава джоба за разпращане на мейли и да събира всички генерирани репорти със статус 3 и да ги разпраща
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:08 AM
11:16
без да се съобразява далки е дневен или седмичен или месечен
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:16:37 AM
11:16 AM
а да, за пращане мисля че няма проверки
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:16:56 AM
11:16
чакай да видя, мисля че само при генериране
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Aneliya Angelova
Today at 11:18:33 AM
11:18 AM
Иначе ако това е обяснението - нека така си остане.
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:20:59 AM
11:20 AM
да send cron job събира неизпратени ресултати
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:21:55 AM
11:21
и преценява само по timezone на recipients кога да го прати но в рамките на същия ден
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:23:35 AM
11:23
просто добавяйки мануално пращане се получават някакви сценарии който преди се случваха очаквано само от cron job
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
New
Aneliya Angelova
Today at 11:24:11 AM
11:24 AM
oki
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:25:06 AM
11:25
ок е това
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Adelina Petrova, Direct Message, 1 of 7 suggestions
Aneliya Angelova is typing
DMSActivityMorerireroxToolsHelpcalMistorbookmarksJiminny …..vXStarredi• jiminny-x-integrati..8 platform-inner-teamE) Channels# ai-chapter# ai-team# alerts# backend# c-learning-peoplei confusion-clinic# curiosity_labadeal-insichts-dev# engineering# frontend# general# infra-changes# jiminny-bg8 people-with-copilo...8 people-with-zoom-# platform-team# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the Deople of iimi...ProtllesWindow& platform-inner-...& 10MessagesChannel OverviewMoreYesterdayjinnylaop Aor 22nd Added by GitHubNikolay Ivanov 3:24 PMнякой нещо да е настроивал по githubactions. Почна да прави къмити вместо менбез да съм му разрешевал?https:/github.com/lminnv/app/pull/1200//changes/a68f42f210859f838a4fdced451f750627besoioИли нещо аз не разбирам?0AA0e 20 replies Last reply 18...Nikolay Yankov 3:50PMreplied to a uhread: някои нешо ла е насто..лол. ами предлагам маи ла му заораним лапускам към всички ла вилятNikolav Yankov 9.38 AMЩе се забавя за дейлито. Започнете без Мен.Aneliva Angelova 9:43 AMIДобро утро, няма да успея да вляза влейлито. Пествам ньлжовете.Message & platform-inner-team+ Aa I..•) New TabAl reports promotion pages by nik• JY-9712 | Nuges to expire after on8 Jiminnyu Userpilot Logged-activityJY-20157 add not enough activ XPipelines - jiminny/app+ New Tab©github.com/jimjiminny / app 8<> Code87 Pull requests 31( Agents |© Actions•• Wiki © Security and quality 32 ~ Insights 3 Settings@ On April 24 we'll start using GitHub Copilot interaction data for Al model training unless you opt out. Review this update and manage your preferences in your GitHub account settings.JY-20157 add not enough activities notification #12011 •$1 Open LakyLak wants to merge 2 commits into master from JY-20157-AJ-report-not-send-notification@) Conversation o• Commits 2|- Checks 21E Files changed 13A © All commits +Q Filter files...apo/Console/Commands/Reports/AutomatedReportsCommand.ohp@ -61,21 +61,29 @ public function handle(): intv = Console/Commands/Renorts|Snow = Carbon: : now();E AutomatedReportsCommand...v Jobs/AutomatedReportsE RequestGenerateAskJiminnyR...SendReportNotGeneratedMail...v @ Listeners/AutomatedReports/U….E TrackAutomatedReportGener...v # Mail/ReportsS1sMondav = Snow->1SMonday)S1sr1rstDayUtMonth = Snow->day === 1;ScurrentMonth = Snow->month.// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);$this->logger->info(self::LOG_PREFIX . ' Checking conditions', [+ ReportNotGenerated.ohp |"1SMonday' => S1SMonday,~ E Services/Kiosk/AutomatedRepo…..AskJiminnyReportActivityServ…'isFirstDay0fMonth' => SisFirstDay0fMonth,'currentMonth' => ScurrentMonth.E AutomatedReportsService.php'isQuarterlyMonth' => SisQuarterlyMonth,~E resources/views/emails/reportsreport-not-generated.blade.php/I Process dailv revortsl• F tests/UnitSthis->processReports(AutomatedReportsService::FREQUENCYDAILY):~ Jobs/AutomatedReportsE ReguestGenerateAsk JiminnvR....v = listeners/AutomatedRenorts/U.₴ TrackAutomatedReportGener..v E Services/Kiosk/AutomatedRepo…..E AskJiminnyReportActivityServ....AutomatedReportsServiceActi…./ Process weekly renorts on Mondavcif (SisMondav) {64 +67 +74 +86 +@40@ Daily - Platform - nowQ Type to search100% C4 8• Fri 24 Apr 9:46:13• Checks pending Code • (Preview) -+384 -52 9000C 0 I 13 viewedSubmit review+10 -2 mane [ Viewed0 ...Snow = Carhon:.nowdSisMondav = Snow->1SMonday)"Sisweekend = $now->isWeekend():SisFirstDay0fMonth = Snow->day === 1;ScurrentMonth = Snow->month.SisManualTrigger = $this->option('report-id') !== null;// Check if the current month is a quarterly month (January, April, July, October)$isQuarterlyMonth = in_array($currentMonth, [1, 4, 7, 10], true);Sthis->loager->info(self::L0G PREFIX . ' Checkina conditions'. [I"isMonday' => SisMonday,'isweekend' => $isWeekend,'isFirstDay0fMonth' => $isFirstDay0fMonth,'currentMonth' => ScurrentMonth.l'isQuarterlyMonth' => SisQuarterlyMonth,/ Process dailv renorts on weekdavs onlv (skio Saturdav/Sundav)...// Manual triggers via --report-id bypass the weekend skip.if (I Sisweekend || SisManualTriager) {Sthis->processReports(AutomatedReportsService::FREQUENCY_DAILY):} else {ISthis->logger->info(self::L0G PREFIX . ' Skipping daily reports on weekend'):/ Process weekly renorts on Mondavslif (SisMonday) {...
|
77500
|