|
56297
|
NULL
|
0
|
2026-05-19T07:52:43.107371+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779177163107_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReport.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.38297874,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.3929521,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.40226063,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.17318435,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.17318435,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.29288563,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7602850585725000454
|
-741603152122655068
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
56295
|
NULL
|
NULL
|
NULL
|
|
56247
|
NULL
|
0
|
2026-05-19T07:47:29.376707+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176849376_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReport.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4892922036090346909
|
-741884627099365724
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56246
|
NULL
|
0
|
2026-05-19T07:47:27.985272+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176847985_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReport.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.38297874,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.3929521,"top":0.17478053,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.40226063,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.4119016,"top":0.17318435,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.4192154,"top":0.17318435,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8401022115491774939
|
-741568003184570844
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Sync Changes
Hide This Notification
Code changed:
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56208
|
NULL
|
0
|
2026-05-19T07:42:33.178542+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176553178_m2.jpg...
|
Firefox
|
Feed — jiminny — Sentry — Work
|
1
|
jiminny.sentry.io/issues/?environment=production-e jiminny.sentry.io/issues/?environment=production-eu&environment=production&project=82419&query=is%3Aunresolved&referrer=issue-list&sort=freq&statsPeriod=7d...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Feed
Pause real-time updates
Ask Seer
Ask Seer
/
Give Feedback
app
app
production-eu, production
production-eu, production
7D
7D
Add a search term
Edit operator for filter: is
is
Edit value for filter: is
unresolved
Remove filter: is
Add a search term
Add a search term
Edit operator for filter: is
is
Add a search term
Edit value for filter: is
unresolved
Remove filter: is
Clear search query
Events
Events
Save as
Save as
Select all
Issue
Last Seen
Age
Trend
24h
24h
7d
7d
Events
Users
Priority
Assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.
View Project Details
APP-1ET5
/app/Services/Crm/BaseService.php in Jiminny\Services\Crm\BaseService::validateUserAccountExists
18min ago
4mo
Ongoing
2.4K
0
Modify issue priority
High
Modify issue assignee
Select Issue
ErrorException
ErrorException
Level: Warning
Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\Mysql::ATTR_SSL_CA instead
View Project Details
APP-1FTA
Unhandled
/home/jiminny/config/database.php in require
3hr ago
2wk
Ongoing
2.4K
0
Modify issue priority
Med
Modify issue assignee
Select Issue
Elastica\Exception\ResponseException
Elastica\Exception\ResponseException
Level: Error
[_doc][80255549]: document missing [index: activities]
View Project Details
APP-1D64
/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\Component\ES\ElasticSearchDocumentPartialUpdater::update
11hr ago
11mo
Ongoing
2.3K
0
Modify issue priority
High
Modify issue assignee
Select Issue
TypeError
TypeError
Level: Error
Jiminny\Services\Activity\Close\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270
View Project Details
APP-1FSA
/app/Services/Activity/Close/Service.php in Jiminny\Services\Activity\Close\Service::getUser
Quick Fix
Quick Fix
12hr ago
3wk
Ongoing
951
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Activity Provider account not connected.
View Project Details
APP-1F3R
/app/Services/Activity/ActivityProviderService.php in Jiminny\Services\Activity\ActivityProviderService::setSocialAccount
36min ago
3mo
Ongoing
631
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Level: Error
LastModifiedDate > 2026-05-14T16:16:47Z AND AccountId != '' ORDER BY LastModifiedDate ^ ERROR at Row:1:Column:215 No such column 'AccountId' on entity 'Opportunity'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.
View Project Details
APP-1FDA
/app/Services/Crm/Salesforce/Client.php in Jiminny\Services\Crm\Salesforce\Client::request
14hr ago
5d
Ongoing
582
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Component\Transcription\TranscriptionProcessor\Gladia\Exceptions\InvalidTranslationResponseException
Jiminny\Component\Transcription\TranscriptionProcessor\Gladia\Exceptions\InvalidTranslationResponseException
Level: Error
Invalid translation response
View Project Details
APP-1CGE
/app/Component/Transcription/Service/TranslationService.php in Jiminny\Component\Transcription\Service\TranslationService::getTranslatedTranscript
8min ago
1yr
Ongoing
357
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Level: Error
invalid cross reference id
View Project Details...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.041888297,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.042719416,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.32083002,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.34796488,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"bounds":{"left":0.08643617,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"bounds":{"left":0.0809508,"top":0.09736632,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"bounds":{"left":0.0866024,"top":0.13048683,"width":0.010305851,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"bounds":{"left":0.0809508,"top":0.14804469,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"bounds":{"left":0.08577128,"top":0.1811652,"width":0.011968086,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"bounds":{"left":0.0809508,"top":0.19872306,"width":0.021609042,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"bounds":{"left":0.08211436,"top":0.23184358,"width":0.019281914,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"bounds":{"left":0.0809508,"top":0.2490024,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"bounds":{"left":0.084773935,"top":0.2821229,"width":0.013962766,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.0809508,"top":0.29968077,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.08494016,"top":0.33280128,"width":0.013630319,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"bounds":{"left":0.08643617,"top":0.88667196,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"bounds":{"left":0.08643617,"top":0.9114126,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"bounds":{"left":0.08643617,"top":0.93615323,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"bounds":{"left":0.08643617,"top":0.9680766,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":12,"bounds":{"left":0.04305186,"top":0.066640064,"width":0.014461436,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":12,"bounds":{"left":0.088597074,"top":0.061452515,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":14,"bounds":{"left":0.039727394,"top":0.10055866,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":16,"bounds":{"left":0.044049203,"top":0.10734238,"width":0.010638298,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":14,"bounds":{"left":0.039727394,"top":0.14046289,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":16,"bounds":{"left":0.044049203,"top":0.14724661,"width":0.03673537,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":14,"bounds":{"left":0.039727394,"top":0.16759777,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":16,"bounds":{"left":0.044049203,"top":0.17438148,"width":0.037898935,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":14,"bounds":{"left":0.039727394,"top":0.19473264,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":16,"bounds":{"left":0.044049203,"top":0.20151636,"width":0.019946808,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":14,"bounds":{"left":0.039727394,"top":0.22186752,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":16,"bounds":{"left":0.044049203,"top":0.22865124,"width":0.032081116,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":12,"bounds":{"left":0.039727394,"top":0.26177174,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":15,"bounds":{"left":0.043716755,"top":0.26855546,"width":0.016289894,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":14,"bounds":{"left":0.039727394,"top":0.28731045,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":16,"bounds":{"left":0.044049203,"top":0.29409418,"width":0.028922873,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":14,"bounds":{"left":0.039727394,"top":0.3272147,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":16,"bounds":{"left":0.044049203,"top":0.3339984,"width":0.019281914,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":13,"bounds":{"left":0.043716755,"top":0.3735036,"width":0.021941489,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":14,"bounds":{"left":0.039727394,"top":0.39225858,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":16,"bounds":{"left":0.044049203,"top":0.3990423,"width":0.012799202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":16,"bounds":{"left":0.08045213,"top":0.39984038,"width":0.012466756,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Feed","depth":11,"bounds":{"left":0.10954122,"top":0.066640064,"width":0.010638298,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Pause real-time updates","depth":11,"bounds":{"left":0.9222075,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask Seer","depth":10,"bounds":{"left":0.93484044,"top":0.059856344,"width":0.04720745,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"bounds":{"left":0.9461436,"top":0.0650439,"width":0.019614361,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"bounds":{"left":0.9740692,"top":0.065442935,"width":0.0021609042,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"bounds":{"left":0.9840425,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"app","depth":11,"bounds":{"left":0.10954122,"top":0.110135674,"width":0.032912236,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":15,"bounds":{"left":0.12283909,"top":0.11691939,"width":0.00831117,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"production-eu, production","depth":11,"bounds":{"left":0.14212102,"top":0.110135674,"width":0.07646277,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"production-eu, production","depth":15,"bounds":{"left":0.14744017,"top":0.11691939,"width":0.059840426,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"7D","depth":11,"bounds":{"left":0.21825133,"top":0.110135674,"width":0.02244016,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"7D","depth":15,"bounds":{"left":0.22357048,"top":0.11691939,"width":0.005817819,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":14,"bounds":{"left":0.2549867,"top":0.114924185,"width":0.0029920214,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit operator for filter: is","depth":16,"bounds":{"left":0.25831118,"top":0.11572227,"width":0.006150266,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"is","depth":18,"bounds":{"left":0.2599734,"top":0.118515566,"width":0.0034906915,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit value for filter: is","depth":15,"bounds":{"left":0.26446143,"top":0.11572227,"width":0.025930852,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"unresolved","depth":17,"bounds":{"left":0.26545876,"top":0.118515566,"width":0.023936171,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Remove filter: is","depth":15,"bounds":{"left":0.29039228,"top":0.11572227,"width":0.0063164895,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Add a search term","depth":14,"bounds":{"left":0.29704124,"top":0.114924185,"width":0.62017953,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"Add a search term","depth":14,"bounds":{"left":0.2549867,"top":0.114924185,"width":0.0029920214,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit operator for filter: is","depth":15,"bounds":{"left":0.25831118,"top":0.11572227,"width":0.006150266,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"is","depth":17,"bounds":{"left":0.2599734,"top":0.118515566,"width":0.0034906915,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":14,"bounds":{"left":0.29704124,"top":0.114924185,"width":0.62017953,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit value for filter: is","depth":14,"bounds":{"left":0.26446143,"top":0.11572227,"width":0.025930852,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"unresolved","depth":16,"bounds":{"left":0.26545876,"top":0.118515566,"width":0.023936171,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Remove filter: is","depth":14,"bounds":{"left":0.29039228,"top":0.11572227,"width":0.0063164895,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Clear search query","depth":12,"bounds":{"left":0.9182181,"top":0.114924185,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Events","depth":11,"bounds":{"left":0.9321808,"top":0.110135674,"width":0.032081116,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":14,"bounds":{"left":0.9375,"top":0.11691939,"width":0.015458777,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Save as","depth":10,"bounds":{"left":0.96692157,"top":0.110135674,"width":0.027759308,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Save as","depth":12,"bounds":{"left":0.9722407,"top":0.11691939,"width":0.017121011,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select all","depth":11,"bounds":{"left":0.115192816,"top":0.16041501,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issue","depth":12,"bounds":{"left":0.123171546,"top":0.16121309,"width":0.011136968,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Last Seen","depth":12,"bounds":{"left":0.77327126,"top":0.16121309,"width":0.020611702,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Age","depth":12,"bounds":{"left":0.80767953,"top":0.16121309,"width":0.008144947,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trend","depth":11,"bounds":{"left":0.82646275,"top":0.16121309,"width":0.011968086,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"24h","depth":12,"bounds":{"left":0.86136967,"top":0.16121309,"width":0.010472074,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24h","depth":13,"bounds":{"left":0.8640292,"top":0.16121309,"width":0.0078125,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"7d","depth":12,"bounds":{"left":0.8718417,"top":0.16121309,"width":0.007480053,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7d","depth":13,"bounds":{"left":0.87450135,"top":0.16121309,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Events","depth":12,"bounds":{"left":0.8902925,"top":0.16121309,"width":0.014295213,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users","depth":12,"bounds":{"left":0.91788566,"top":0.16121309,"width":0.011968086,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Priority","depth":12,"bounds":{"left":0.94049203,"top":0.16121309,"width":0.015625,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assignee","depth":12,"bounds":{"left":0.96708775,"top":0.16121309,"width":0.019115692,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.17438148,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":12,"bounds":{"left":0.123171546,"top":0.19114126,"width":0.13048537,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":14,"bounds":{"left":0.123171546,"top":0.19233839,"width":0.13048537,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.207502,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.","depth":14,"bounds":{"left":0.12616356,"top":0.20710295,"width":0.19365026,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.22585794,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1ET5","depth":13,"bounds":{"left":0.12815824,"top":0.22585794,"width":0.016788565,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Crm/BaseService.php in Jiminny\\Services\\Crm\\BaseService::validateUserAccountExists","depth":13,"bounds":{"left":0.14893617,"top":0.2254589,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18min ago","depth":12,"bounds":{"left":0.77160907,"top":0.20830008,"width":0.022273935,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4mo","depth":12,"bounds":{"left":0.8061835,"top":0.20830008,"width":0.009640957,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.22346368,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.4K","depth":13,"bounds":{"left":0.8947806,"top":0.207502,"width":0.009807181,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.207502,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.2047087,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.2150838,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97041225,"top":0.2047087,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.23982441,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"ErrorException","depth":12,"bounds":{"left":0.123171546,"top":0.2565842,"width":0.033909574,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ErrorException","depth":14,"bounds":{"left":0.123171546,"top":0.25778133,"width":0.033909574,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Warning","depth":15,"bounds":{"left":0.12283909,"top":0.27294493,"width":0.03125,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\\Mysql::ATTR_SSL_CA instead","depth":14,"bounds":{"left":0.12616356,"top":0.2725459,"width":0.24966756,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.29130086,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1FTA","depth":13,"bounds":{"left":0.12815824,"top":0.29130086,"width":0.016788565,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unhandled","depth":12,"bounds":{"left":0.14893617,"top":0.29090184,"width":0.020113032,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/home/jiminny/config/database.php in require","depth":13,"bounds":{"left":0.17303856,"top":0.29090184,"width":0.08643617,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3hr ago","depth":12,"bounds":{"left":0.77726066,"top":0.273743,"width":0.01662234,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2wk","depth":12,"bounds":{"left":0.80701464,"top":0.273743,"width":0.00880984,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.28890663,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.4K","depth":13,"bounds":{"left":0.8947806,"top":0.27294493,"width":0.009807181,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.27294493,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.27015164,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Med","depth":16,"bounds":{"left":0.9494681,"top":0.28052673,"width":0.007978723,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97041225,"top":0.27015164,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.33719075,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Elastica\\Exception\\ResponseException","depth":12,"bounds":{"left":0.123171546,"top":0.32202715,"width":0.08909574,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Elastica\\Exception\\ResponseException","depth":14,"bounds":{"left":0.123171546,"top":0.32322428,"width":0.08909574,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.33838788,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[_doc][80255549]: document missing [index: activities]","depth":14,"bounds":{"left":0.12616356,"top":0.33798882,"width":0.12017952,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.3567438,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1D64","depth":13,"bounds":{"left":0.12815824,"top":0.3567438,"width":0.017287234,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\\Component\\ES\\ElasticSearchDocumentPartialUpdater::update","depth":13,"bounds":{"left":0.14943483,"top":0.35634476,"width":0.26030585,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11hr ago","depth":12,"bounds":{"left":0.77609706,"top":0.33918595,"width":0.017785905,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11mo","depth":12,"bounds":{"left":0.80502,"top":0.33918595,"width":0.010804521,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.35434955,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.3K","depth":13,"bounds":{"left":0.8947806,"top":0.33838788,"width":0.009807181,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.33838788,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.33559456,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.34596968,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97107714,"top":0.33559456,"width":0.012632979,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.37071028,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TypeError","depth":12,"bounds":{"left":0.123171546,"top":0.38747007,"width":0.022107713,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError","depth":14,"bounds":{"left":0.123171546,"top":0.3886672,"width":0.022107713,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.4038308,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Services\\Activity\\Close\\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270","depth":14,"bounds":{"left":0.12616356,"top":0.40343177,"width":0.40458778,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.42218676,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1FSA","depth":13,"bounds":{"left":0.12815824,"top":0.42218676,"width":0.017121011,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Activity/Close/Service.php in Jiminny\\Services\\Activity\\Close\\Service::getUser","depth":13,"bounds":{"left":0.14926861,"top":0.4217877,"width":0.17636304,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Quick Fix","depth":12,"bounds":{"left":0.32762632,"top":0.42218676,"width":0.024102394,"height":0.009577015},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Quick Fix","depth":14,"bounds":{"left":0.33494017,"top":0.4217877,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12hr ago","depth":12,"bounds":{"left":0.77543217,"top":0.4046289,"width":0.018450798,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3wk","depth":12,"bounds":{"left":0.8068484,"top":0.4046289,"width":0.008976064,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.4197925,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"951","depth":13,"bounds":{"left":0.8959442,"top":0.4038308,"width":0.008643617,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.4038308,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.4010375,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.4114126,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97041225,"top":0.4010375,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.43615323,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":12,"bounds":{"left":0.123171546,"top":0.45291302,"width":0.13048537,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":14,"bounds":{"left":0.123171546,"top":0.45411015,"width":0.13048537,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.46927375,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity Provider account not connected.","depth":14,"bounds":{"left":0.12616356,"top":0.4688747,"width":0.08892952,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.48762968,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1F3R","depth":13,"bounds":{"left":0.12815824,"top":0.48762968,"width":0.016954787,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Activity/ActivityProviderService.php in Jiminny\\Services\\Activity\\ActivityProviderService::setSocialAccount","depth":13,"bounds":{"left":0.14910239,"top":0.48723066,"width":0.23005319,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"36min ago","depth":12,"bounds":{"left":0.7709442,"top":0.47007182,"width":0.022938829,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3mo","depth":12,"bounds":{"left":0.8061835,"top":0.47007182,"width":0.009640957,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.48523542,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"631","depth":13,"bounds":{"left":0.8959442,"top":0.46927375,"width":0.008643617,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.46927375,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.46648043,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.47685555,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97041225,"top":0.46648043,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.50159615,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Exceptions\\HttpBadRequestWithErrorReasonException","depth":12,"bounds":{"left":0.123171546,"top":0.51835597,"width":0.14577793,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\HttpBadRequestWithErrorReasonException","depth":14,"bounds":{"left":0.123171546,"top":0.51955307,"width":0.14577793,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.53471667,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LastModifiedDate > 2026-05-14T16:16:47Z AND AccountId != '' ORDER BY LastModifiedDate ^ ERROR at Row:1:Column:215 No such column 'AccountId' on entity 'Opportunity'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.","depth":14,"bounds":{"left":0.12616356,"top":0.5343176,"width":0.75299203,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.55307263,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1FDA","depth":13,"bounds":{"left":0.12815824,"top":0.55307263,"width":0.017287234,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Crm/Salesforce/Client.php in Jiminny\\Services\\Crm\\Salesforce\\Client::request","depth":13,"bounds":{"left":0.14943483,"top":0.5526736,"width":0.17586437,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14hr ago","depth":12,"bounds":{"left":0.77526593,"top":0.5355148,"width":0.01861702,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5d","depth":12,"bounds":{"left":0.8103391,"top":0.5355148,"width":0.005485372,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.5506784,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"582","depth":13,"bounds":{"left":0.8959442,"top":0.53471667,"width":0.008643617,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.53471667,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.5319234,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.5422985,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.97041225,"top":0.5319234,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.56703913,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Component\\Transcription\\TranscriptionProcessor\\Gladia\\Exceptions\\InvalidTranslationResponseException","depth":12,"bounds":{"left":0.123171546,"top":0.5837989,"width":0.26313165,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Component\\Transcription\\TranscriptionProcessor\\Gladia\\Exceptions\\InvalidTranslationResponseException","depth":14,"bounds":{"left":0.123171546,"top":0.584996,"width":0.26313165,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.60015965,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Invalid translation response","depth":14,"bounds":{"left":0.12616356,"top":0.5997606,"width":0.059840426,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.61851555,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1CGE","depth":13,"bounds":{"left":0.12815824,"top":0.61851555,"width":0.017453458,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Component/Transcription/Service/TranslationService.php in Jiminny\\Component\\Transcription\\Service\\TranslationService::getTranslatedTranscript","depth":13,"bounds":{"left":0.14960106,"top":0.6181165,"width":0.28607047,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8min ago","depth":12,"bounds":{"left":0.77360374,"top":0.6009577,"width":0.020279255,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1yr","depth":12,"bounds":{"left":0.80950797,"top":0.6009577,"width":0.0063164895,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"bounds":{"left":0.82646275,"top":0.6161213,"width":0.015625,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"357","depth":13,"bounds":{"left":0.8959442,"top":0.60015965,"width":0.008643617,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.92702794,"top":0.60015965,"width":0.0028257978,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"bounds":{"left":0.9424867,"top":0.59736633,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"bounds":{"left":0.9494681,"top":0.6077414,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"bounds":{"left":0.96974736,"top":0.59736633,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"bounds":{"left":0.115192816,"top":0.63248205,"width":0.005319149,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Exceptions\\HttpBadRequestWithErrorReasonException","depth":12,"bounds":{"left":0.123171546,"top":0.6492418,"width":0.14577793,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\HttpBadRequestWithErrorReasonException","depth":14,"bounds":{"left":0.123171546,"top":0.65043896,"width":0.14577793,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.12283909,"top":0.66560256,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"invalid cross reference id","depth":14,"bounds":{"left":0.12616356,"top":0.6652035,"width":0.054022606,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.123171546,"top":0.6839585,"width":0.0039893617,"height":0.009577015},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-6850187925261072870
|
8239153619897474295
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Feed
Pause real-time updates
Ask Seer
Ask Seer
/
Give Feedback
app
app
production-eu, production
production-eu, production
7D
7D
Add a search term
Edit operator for filter: is
is
Edit value for filter: is
unresolved
Remove filter: is
Add a search term
Add a search term
Edit operator for filter: is
is
Add a search term
Edit value for filter: is
unresolved
Remove filter: is
Clear search query
Events
Events
Save as
Save as
Select all
Issue
Last Seen
Age
Trend
24h
24h
7d
7d
Events
Users
Priority
Assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.
View Project Details
APP-1ET5
/app/Services/Crm/BaseService.php in Jiminny\Services\Crm\BaseService::validateUserAccountExists
18min ago
4mo
Ongoing
2.4K
0
Modify issue priority
High
Modify issue assignee
Select Issue
ErrorException
ErrorException
Level: Warning
Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\Mysql::ATTR_SSL_CA instead
View Project Details
APP-1FTA
Unhandled
/home/jiminny/config/database.php in require
3hr ago
2wk
Ongoing
2.4K
0
Modify issue priority
Med
Modify issue assignee
Select Issue
Elastica\Exception\ResponseException
Elastica\Exception\ResponseException
Level: Error
[_doc][80255549]: document missing [index: activities]
View Project Details
APP-1D64
/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\Component\ES\ElasticSearchDocumentPartialUpdater::update
11hr ago
11mo
Ongoing
2.3K
0
Modify issue priority
High
Modify issue assignee
Select Issue
TypeError
TypeError
Level: Error
Jiminny\Services\Activity\Close\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270
View Project Details
APP-1FSA
/app/Services/Activity/Close/Service.php in Jiminny\Services\Activity\Close\Service::getUser
Quick Fix
Quick Fix
12hr ago
3wk
Ongoing
951
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Activity Provider account not connected.
View Project Details
APP-1F3R
/app/Services/Activity/ActivityProviderService.php in Jiminny\Services\Activity\ActivityProviderService::setSocialAccount
36min ago
3mo
Ongoing
631
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Level: Error
LastModifiedDate > 2026-05-14T16:16:47Z AND AccountId != '' ORDER BY LastModifiedDate ^ ERROR at Row:1:Column:215 No such column 'AccountId' on entity 'Opportunity'. If you are attempting to use a custom field, be sure to append the '__c' after the custom field name. Please reference your WSDL or the describe call for the appropriate names.
View Project Details
APP-1FDA
/app/Services/Crm/Salesforce/Client.php in Jiminny\Services\Crm\Salesforce\Client::request
14hr ago
5d
Ongoing
582
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Component\Transcription\TranscriptionProcessor\Gladia\Exceptions\InvalidTranslationResponseException
Jiminny\Component\Transcription\TranscriptionProcessor\Gladia\Exceptions\InvalidTranslationResponseException
Level: Error
Invalid translation response
View Project Details
APP-1CGE
/app/Component/Transcription/Service/TranslationService.php in Jiminny\Component\Transcription\Service\TranslationService::getTranslatedTranscript
8min ago
1yr
Ongoing
357
0
Modify issue priority
High
Modify issue assignee
Select Issue
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Jiminny\Exceptions\HttpBadRequestWithErrorReasonException
Level: Error
invalid cross reference id
View Project Details...
|
56206
|
NULL
|
NULL
|
NULL
|
|
56207
|
NULL
|
0
|
2026-05-19T07:42:32.099343+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176552099_m1.jpg...
|
Firefox
|
Feed — jiminny — Sentry — Work
|
1
|
jiminny.sentry.io/issues/?environment=production-e jiminny.sentry.io/issues/?environment=production-eu&environment=production&project=82419&query=is%3Aunresolved&referrer=issue-list&sort=freq&statsPeriod=7d...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Feed
Pause real-time updates
Ask Seer
Ask Seer
/
Give Feedback
app
app
production-eu, production
production-eu, production
7D
7D
Add a search term
Edit operator for filter: is
is
Edit value for filter: is
unresolved
Remove filter: is
Add a search term
Add a search term
Edit operator for filter: is
is
Add a search term
Edit value for filter: is
unresolved
Remove filter: is
Clear search query
Events
Events
Save as
Save as
Select all
Issue
Last Seen
Age
Trend
24h
24h
7d
7d
Events
Users
Priority
Assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.
View Project Details
APP-1ET5
/app/Services/Crm/BaseService.php in Jiminny\Services\Crm\BaseService::validateUserAccountExists
18min ago
4mo
Ongoing
2.4K
0
Modify issue priority
High
Modify issue assignee
Select Issue
ErrorException
ErrorException
Level: Warning
Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\Mysql::ATTR_SSL_CA instead
View Project Details
APP-1FTA
Unhandled
/home/jiminny/config/database.php in require
3hr ago
2wk
Ongoing
2.4K
0
Modify issue priority
Med
Modify issue assignee
Select Issue
Elastica\Exception\ResponseException
Elastica\Exception\ResponseException
Level: Error
[_doc][80255549]: document missing [index: activities]
View Project Details
APP-1D64
/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\Component\ES\ElasticSearchDocumentPartialUpdater::update
11hr ago
11mo
Ongoing
2.3K
0
Modify issue priority
High
Modify issue assignee
Select Issue
TypeError
TypeError
Level: Error
Jiminny\Services\Activity\Close\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270
View Project Details
APP-1FSA
/app/Services/Activity/Close/Service.php in Jiminny\Services\Activity\Close\Service::getUser
Quick Fix
Quick Fix
12hr ago...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":14,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Feed","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Pause real-time updates","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Ask Seer","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"app","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"production-eu, production","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"production-eu, production","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"7D","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"7D","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":14,"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit operator for filter: is","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"is","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit value for filter: is","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"unresolved","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Remove filter: is","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Add a search term","depth":14,"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"Add a search term","depth":14,"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit operator for filter: is","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"is","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":14,"on_screen":true,"help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit value for filter: is","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"unresolved","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Remove filter: is","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Clear search query","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Events","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Save as","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Save as","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select all","depth":11,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issue","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Last Seen","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Age","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trend","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"24h","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24h","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"7d","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7d","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Events","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Priority","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assignee","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Select Issue","depth":12,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny\\Exceptions\\SocialAccountTokenInvalidException","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1ET5","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Crm/BaseService.php in Jiminny\\Services\\Crm\\BaseService::validateUserAccountExists","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18min ago","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4mo","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.4K","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"ErrorException","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ErrorException","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Warning","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\\Mysql::ATTR_SSL_CA instead","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1FTA","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unhandled","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/home/jiminny/config/database.php in require","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3hr ago","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2wk","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.4K","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Med","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Elastica\\Exception\\ResponseException","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Elastica\\Exception\\ResponseException","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[_doc][80255549]: document missing [index: activities]","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1D64","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\\Component\\ES\\ElasticSearchDocumentPartialUpdater::update","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11hr ago","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11mo","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.3K","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Select Issue","depth":12,"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"TypeError","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Services\\Activity\\Close\\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1FSA","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Services/Activity/Close/Service.php in Jiminny\\Services\\Activity\\Close\\Service::getUser","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Quick Fix","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Quick Fix","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12hr ago","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-5168494075341230613
|
8526820981639798261
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Feed
Pause real-time updates
Ask Seer
Ask Seer
/
Give Feedback
app
app
production-eu, production
production-eu, production
7D
7D
Add a search term
Edit operator for filter: is
is
Edit value for filter: is
unresolved
Remove filter: is
Add a search term
Add a search term
Edit operator for filter: is
is
Add a search term
Edit value for filter: is
unresolved
Remove filter: is
Clear search query
Events
Events
Save as
Save as
Select all
Issue
Last Seen
Age
Trend
24h
24h
7d
7d
Events
Users
Priority
Assignee
Select Issue
Jiminny\Exceptions\SocialAccountTokenInvalidException
Jiminny\Exceptions\SocialAccountTokenInvalidException
Level: Error
Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.
View Project Details
APP-1ET5
/app/Services/Crm/BaseService.php in Jiminny\Services\Crm\BaseService::validateUserAccountExists
18min ago
4mo
Ongoing
2.4K
0
Modify issue priority
High
Modify issue assignee
Select Issue
ErrorException
ErrorException
Level: Warning
Deprecated: Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\Mysql::ATTR_SSL_CA instead
View Project Details
APP-1FTA
Unhandled
/home/jiminny/config/database.php in require
3hr ago
2wk
Ongoing
2.4K
0
Modify issue priority
Med
Modify issue assignee
Select Issue
Elastica\Exception\ResponseException
Elastica\Exception\ResponseException
Level: Error
[_doc][80255549]: document missing [index: activities]
View Project Details
APP-1D64
/app/Component/ES/ElasticSearchDocumentPartialUpdater.php in Jiminny\Component\ES\ElasticSearchDocumentPartialUpdater::update
11hr ago
11mo
Ongoing
2.3K
0
Modify issue priority
High
Modify issue assignee
Select Issue
TypeError
TypeError
Level: Error
Jiminny\Services\Activity\Close\Service::getUser(): Argument #1 ($userId) must be of type string, null given, called in /home/jiminny/app/Services/Activity/Close/Service.php on line 270
View Project Details
APP-1FSA
/app/Services/Activity/Close/Service.php in Jiminny\Services\Activity\Close\Service::getUser
Quick Fix
Quick Fix
12hr ago...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56181
|
NULL
|
0
|
2026-05-19T07:37:36.381993+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176256381_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncActivity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicareCodeLaravelFV faVsco.js~°9 ma PhostormVIewINavicareCodeLaravelFV faVsco.js~°9 master kProject© LiveCoachController.php© MissingTeamController.phpc) Mobilecontroller.ong© NotificationController.phpONowricationrrovidercontroller.onp© PlaybackConttroller.php© PlaylistController.php© PusherController.php© SlackController.php© SupportController.php© TeamSetupController.phpc) Userautomateakeporiscontroller.pnoc) welcomecontroller.onoU MicclewareSerializersM Transformers(C) Kernelohr©PlaylistTrackResourceTrait.phpT ValidateCrmConnectionReguiredtrait.oho• IntegrationsInteractionsJobsv Activity> Dialpad>D ImportO JustCallPushSummaryToCrm• D RingCentralm 7oomDhanc© ActivityChangeCategorylds.phpAssicnownersnip.onp© ConferenceCrmMatcherJob.phpC) DeleteActivities.php© DeleteTeamChurnData.phpC) DeleteTeamsRetentionData.phpC) HardDeleteActivities.phg© HardDeleteActivity.phpC)MatchMeetngowner.onvc) ReindexForAccount.o..ohoC) ReindexForContact.Job.ohvC) ReindexForGrouo.Job.ohoC) ReindexForLead.Job.ohnC) [EMAIL]) ReindexForUser.Job.oho(c) RotrvActivitvSvne.loh.nhn(c) SvncActivitv nho(C) TeardownStream nhnM AiAutomationKeractor© BaseService.php© SoftPhoneManager.php© CoreUserRequest.phpconstants.ongy coreuser.pnpActivity/Close/service.pnp© Activity/RingCentral/Service.phpsyncacuivity.php165166167168215class SyncActivity extends Job implements ShouldQueueorivatetunction runo.ActivirvimoortResultsch1s->1mport->gectnovate,$this-›userRepository->findOneBy(['id' => $this->import->getUserIdO]),sch1s->1mport->gecAcc1V1cy100return new ActivitvimportResultoo->settotal SimportedRecords).->addImported($importedRecords)usayeprivate function complete(ActivityImportResult $result): voidSthis->activitvimoortManager->comolete(Sthis->imoort. Sresult):Datadog:: increment( stats: "jiminny.activity.sync.success','company' => $this->context['team'],'provider' => $this->context['provider'],sampleRate: 1.0, [D);$this->logger->info('[SyncActivity] End', $this->context);$this->logger->info("Lsyncaccivity. renory usage"arraymeroeu'memory usage => memory get usageo.'memoryreal usage' => memory qet usagec real usage: true)'pid' => getmypid(),orivate function faluumoortuhrowable Sexcention: void .?The Hunsnell nluain hac heon denrecated. If vou're not writing in Hungarian vou canEcustom.logA console [STAGING]<?phpE laravel.log4 SF [jiminny@localhost]© CoachingFeedbackCoachUserin.phpxA HS_Jocal [jiminny@localhost]A console [PROD]& console [EU]A1. Ydeclare(scrict_cypes=l)nnamespace Jiminny Component Activ1tySearch rilterbetin1t1on*final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface29 đ >34 đ >45 đ >135136 € >146 @ >150151 G>1usadeorivate const int No GROUp 1d = 999-private UserRepository $userRepository;public function __construct(UserRepository $userRepository){.}public function shouldApplyQueries(): boolf...}public function getQueries(): FilterDefinitionQueryCollectionf...}public function toArray(): arrayf..,private function getOptions(): arrayf…..,public function getValue(): arrayf...}private function getDefaultValue(): arrayf….,public function getValidationRules(?string $prefix = null): arrayf…..,public function getSortOrder(): intf...}public function shouldßBeIncluded(Team $team): boolf...}CascadeCascadef Support Daily - in 4h 23mU AskJiminnyReportActivityServiceTest~100% Lz&• Tue 19 May 10:37:36+0 ..wCascade Code *•Kick off a new project. Make changesacross your entre codedase• SCIM Role Management Implementationc Salesforce Token Fallback© Fixing Redis Rate Limit ErrorAsk anvthina (884-L)WN Windsurf Toams 178-25UTF.8f?4 spaces...
|
NULL
|
-956710474745480910
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicareCodeLaravelFV faVsco.js~°9 ma PhostormVIewINavicareCodeLaravelFV faVsco.js~°9 master kProject© LiveCoachController.php© MissingTeamController.phpc) Mobilecontroller.ong© NotificationController.phpONowricationrrovidercontroller.onp© PlaybackConttroller.php© PlaylistController.php© PusherController.php© SlackController.php© SupportController.php© TeamSetupController.phpc) Userautomateakeporiscontroller.pnoc) welcomecontroller.onoU MicclewareSerializersM Transformers(C) Kernelohr©PlaylistTrackResourceTrait.phpT ValidateCrmConnectionReguiredtrait.oho• IntegrationsInteractionsJobsv Activity> Dialpad>D ImportO JustCallPushSummaryToCrm• D RingCentralm 7oomDhanc© ActivityChangeCategorylds.phpAssicnownersnip.onp© ConferenceCrmMatcherJob.phpC) DeleteActivities.php© DeleteTeamChurnData.phpC) DeleteTeamsRetentionData.phpC) HardDeleteActivities.phg© HardDeleteActivity.phpC)MatchMeetngowner.onvc) ReindexForAccount.o..ohoC) ReindexForContact.Job.ohvC) ReindexForGrouo.Job.ohoC) ReindexForLead.Job.ohnC) [EMAIL]) ReindexForUser.Job.oho(c) RotrvActivitvSvne.loh.nhn(c) SvncActivitv nho(C) TeardownStream nhnM AiAutomationKeractor© BaseService.php© SoftPhoneManager.php© CoreUserRequest.phpconstants.ongy coreuser.pnpActivity/Close/service.pnp© Activity/RingCentral/Service.phpsyncacuivity.php165166167168215class SyncActivity extends Job implements ShouldQueueorivatetunction runo.ActivirvimoortResultsch1s->1mport->gectnovate,$this-›userRepository->findOneBy(['id' => $this->import->getUserIdO]),sch1s->1mport->gecAcc1V1cy100return new ActivitvimportResultoo->settotal SimportedRecords).->addImported($importedRecords)usayeprivate function complete(ActivityImportResult $result): voidSthis->activitvimoortManager->comolete(Sthis->imoort. Sresult):Datadog:: increment( stats: "jiminny.activity.sync.success','company' => $this->context['team'],'provider' => $this->context['provider'],sampleRate: 1.0, [D);$this->logger->info('[SyncActivity] End', $this->context);$this->logger->info("Lsyncaccivity. renory usage"arraymeroeu'memory usage => memory get usageo.'memoryreal usage' => memory qet usagec real usage: true)'pid' => getmypid(),orivate function faluumoortuhrowable Sexcention: void .?The Hunsnell nluain hac heon denrecated. If vou're not writing in Hungarian vou canEcustom.logA console [STAGING]<?phpE laravel.log4 SF [jiminny@localhost]© CoachingFeedbackCoachUserin.phpxA HS_Jocal [jiminny@localhost]A console [PROD]& console [EU]A1. Ydeclare(scrict_cypes=l)nnamespace Jiminny Component Activ1tySearch rilterbetin1t1on*final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface29 đ >34 đ >45 đ >135136 € >146 @ >150151 G>1usadeorivate const int No GROUp 1d = 999-private UserRepository $userRepository;public function __construct(UserRepository $userRepository){.}public function shouldApplyQueries(): boolf...}public function getQueries(): FilterDefinitionQueryCollectionf...}public function toArray(): arrayf..,private function getOptions(): arrayf…..,public function getValue(): arrayf...}private function getDefaultValue(): arrayf….,public function getValidationRules(?string $prefix = null): arrayf…..,public function getSortOrder(): intf...}public function shouldßBeIncluded(Team $team): boolf...}CascadeCascadef Support Daily - in 4h 23mU AskJiminnyReportActivityServiceTest~100% Lz&• Tue 19 May 10:37:36+0 ..wCascade Code *•Kick off a new project. Make changesacross your entre codedase• SCIM Role Management Implementationc Salesforce Token Fallback© Fixing Redis Rate Limit ErrorAsk anvthina (884-L)WN Windsurf Toams 178-25UTF.8f?4 spaces...
|
56172
|
NULL
|
NULL
|
NULL
|
|
56180
|
NULL
|
0
|
2026-05-19T07:37:36.371365+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779176256371_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncActivity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7673782238848625796
|
-8646559087753982588
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
iTerm2Shel Project: faVsco.js, menu
master, menu
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp• Support Daily - in 4 h 23 m100% C78• Tue 19 May 10:37:35-zshDOCKERO $1DEV (-zsh)₴82APP (-zsh)*3screenpipe"₴84-zsh*5=>[api internal] load builddefinitionfromDockerfile0.0s= => transferring dockerfile: 567B0.05=> [api] resolve image [URL_WITH_CREDENTIALS] [api internal] load build definitionfrom Dockerfile0.0s=> WARN: JSONArgsRecommended:JSONarguments recommended for CMD to prevent unintended behavior related to OS signals (line 21)0.0s=> [mcp internal] load metadata fordocker.io/library/python:3.11-slim0.05=> [api internal] loaddockerignore0.05= => transferring context: 2B0.0s= [api 1/7] FROM docker.io/library/python:3.11-slim0.0s= [api internal] load build context0.15= = transferring context: 60.33kB0.05=> CACHED [api 2/7] WORKDIR/app0.05=> CACHED [api 3/7] COPY requirements.txt /app/0.0s=> CACHED [api 4/7] RUNpip install --no-cache-dir -r requirements.txt0.0s=> [api 5/7] COPY app /app/app|0.25=> [api 6/7] COPY alembic/app/alembic0.25[api 7/7] COPY alembic.ini /app/alembic.ini0.2s=> [api] exporting to image0.25= => exporting layers0.2s= => writing image sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec0.0s= = namingto docker.io/library/location-logger-api0.05=> [mcp internal] load build definition from Dockerfile0.05= => transferring dockerfile: 715B0.0s[mcp internal] loaddockerignore0.0s=> transferring context: 2B0.0s[mcp internal] load build context0.05= transferring context: 115B0.0s[mcр 1/6]FROM docker.io/library/python:3.11-slim0.05=>CACHED [mcp 2/6] WORKDIR /app0.05CACHED [mcp 3/6] COPY requirements.txt /app/0.0sCACHED[mср4/6]RUN pip install--no-cache-dir -r requirements.txt0.05=> CACHED[mcp5/6J RUNSITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")&& sed-i=> CACHED [mcр6/6J COPYserver.py /app/'s/enable_dns_rebinding_protection=True/enable_dns_rebindin0.0s0.0s=> [mcp] exporting to image0.0s=>=> exportinglayers0.0s= => writingimage sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc00.05=> =› naming to docker.io/library/location-logger-mcp0.0s[+] Running 3/3• Container location-logger-postgresHealthy• Container location-logger-apiHealthy• Container location-logger-mcpStarted0.0510.6s0.85Adm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ Connection to [IP_ADDRESS] closed by remote host.Connection to [IP_ADDRESS] closed.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ [...
|
56157
|
NULL
|
NULL
|
NULL
|
|
56158
|
NULL
|
0
|
2026-05-19T07:32:30.850834+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175950850_m2.jpg...
|
PhpStorm
|
faVsco.js – SyncActivity.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.29288563,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.08843085,"top":0.05027933,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.09940159,"top":0.05027933,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.10804521,"top":0.05027933,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.11668883,"top":0.05027933,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.12533244,"top":0.05027933,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4316251472625321264
|
-259430402414309411
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
56156
|
NULL
|
NULL
|
NULL
|
|
56157
|
NULL
|
0
|
2026-05-19T07:32:30.389001+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175950389_m1.jpg...
|
PhpStorm
|
faVsco.js – SyncActivity.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4316251472625321264
|
-259430402414309411
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56124
|
NULL
|
0
|
2026-05-19T07:27:31.237160+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175651237_m2.jpg...
|
PhpStorm
|
faVsco.js – CoachingFeedbackCoachUserIn.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Activity;\n\nuse ChaseConey\\LaravelDatadogHelper\\Datadog;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Component\\Sentry\\SentryClient;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Contracts\\Services\\ImportsDataInterface;\nuse Jiminny\\DTO\\Activity\\Import\\ActivityImportResult;\nuse Jiminny\\Exceptions\\ActivityProviderException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity\\ActivityImport;\nuse Jiminny\\Models\\Activity\\Provider;\nuse Jiminny\\Services\\Activity\\ActivityProviderRegistry;\nuse Jiminny\\Services\\Import\\ActivityImportManager;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Psr\\Log\\LoggerInterface;\nuse Throwable;\n\nclass SyncActivity extends Job implements ShouldQueue\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';\n\n public int $tries = 3;\n public $queue = Constants::QUEUE_DIALERS;\n\n private ActivityImport $import;\n private ?ActivityImportManager $activityImportManager = null;\n private ?UserRepository $userRepository = null;\n private ?SentryClient $sentryClient = null;\n private ?LoggerInterface $logger = null;\n private ?Provider $provider = null;\n private ?ImportsDataInterface $service = null;\n private array $context;\n\n public function __construct(ActivityImport $import)\n {\n $this->import = $import;\n $this->context = ['import_id' => $import->getId()];\n }\n\n public function handle(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n try {\n $this->init(\n $activityImportManager,\n $activityProviderRegistry,\n $userRepository,\n $sentry,\n $logger,\n );\n } catch (Throwable $exception) {\n $this->failImport($exception);\n\n return;\n }\n\n Datadog::increment('jiminny.activity.sync.start', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n try {\n $result = $this->run();\n $this->complete($result);\n } catch (Throwable $exception) {\n $this->failImport($exception);\n }\n }\n\n public function failed(Throwable $exception): void\n {\n $this->logger ??= app(LoggerInterface::class);\n $this->activityImportManager ??= app(ActivityImportManager::class);\n $this->sentryClient ??= app(SentryClient::class);\n\n if (! isset($this->context)) {\n // This can happen in case of improper deserialization.\n $this->context = [];\n }\n $this->context['team'] ??= 'unknown';\n $this->context['provider'] ??= 'unknown';\n\n if (isset($this->import)) {\n // This can happen in case of improper deserialization.\n $this->failImport($exception);\n }\n }\n\n /**\n * @throws ActivityProviderException\n * @throws SocialAccountTokenInvalidException\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n */\n private function init(\n ActivityImportManager $activityImportManager,\n ActivityProviderRegistry $activityProviderRegistry,\n UserRepository $userRepository,\n SentryClient $sentry,\n LoggerInterface $logger,\n ): void {\n $this->logger = $logger;\n $this->activityImportManager = $activityImportManager;\n $this->userRepository = $userRepository;\n $this->sentryClient = $sentry;\n $provider = $this->import->getActivityProvider();\n\n $this->context['provider'] = $provider->getProviderSlug();\n $this->context['provider_id'] = $provider->getId();\n $this->context['team'] = $provider->getTeam()->getSlug();\n $this->context['team_id'] = $provider->getTeamId();\n\n if (! $provider->isEnabled()) {\n throw new ActivityProviderException('Activity provider is disabled', $provider);\n }\n\n $this->provider = $provider;\n $service = $activityProviderRegistry->get($provider->getProviderSlug());\n\n if (! $service instanceof ImportsDataInterface) {\n throw new ActivityProviderException('Activity provider does not support data imports', $provider);\n }\n\n $service->setTeam($provider->getTeam());\n $service->setSocialAccount($provider->getConnectedSocialAccount());\n $service->setDebug($this->import->runsInDebug());\n $this->service = $service;\n }\n\n private function run(): ActivityImportResult\n {\n $this->logger->info('[SyncActivity] Start', $this->context);\n $this->activityImportManager->start($this->import);\n\n $importedRecords = $this->service->importData(\n $this->import->getStartDate(),\n $this->import->getEndDate(),\n $this->userRepository->findOneBy(['id' => $this->import->getUserId()]),\n $this->import->getActivityId()\n );\n\n return (new ActivityImportResult())\n ->setTotal($importedRecords)\n ->addImported($importedRecords)\n ;\n }\n\n private function complete(ActivityImportResult $result): void\n {\n $this->activityImportManager->complete($this->import, $result);\n\n Datadog::increment('jiminny.activity.sync.success', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n ]);\n\n $this->logger->info('[SyncActivity] End', $this->context);\n\n $this->logger->info(\n '[SyncActivity] Memory usage',\n array_merge(\n $this->context,\n [\n 'memory_usage' => memory_get_usage(),\n 'memory_real_usage' => memory_get_usage(true),\n 'pid' => getmypid(),\n ],\n ),\n );\n }\n\n private function failImport(Throwable $exception): void\n {\n $this->logger->alert(\n message: '[SyncActivity] Failed',\n context: array_merge($this->context, [\n 'reason' => $exception->getMessage(),\n 'file' => $exception->getFile(),\n 'line' => $exception->getLine(),\n ]),\n );\n\n $this->activityImportManager->fail($this->import);\n\n Datadog::increment('jiminny.activity.sync.exception', 1.0, [\n 'company' => $this->context['team'],\n 'provider' => $this->context['provider'],\n 'exception' => $exception::class,\n 'exceptionCode' => $exception->getCode(),\n ]);\n\n if ($exception instanceof SocialAccountTokenInvalidException) {\n return;\n }\n\n $this->sentryClient->captureException($exception);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.7124335,"top":0.10055866,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.09896249,"width":0.00731383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.7287234,"top":0.09896249,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","depth":4,"bounds":{"left":0.4481383,"top":0.09736632,"width":0.29288563,"height":0.8818835},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\ActivitySearch\\FilterDefinition;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQuery;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionQueryCollection;\nuse Jiminny\\Contracts\\ActivitySearch\\ValidatedFilterDefinitionInterface;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Traits\\RequiresUUID;\nuse Elastica\\Query;\n\nfinal class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface\n{\n private const int NO_GROUP_ID = 999;\n private UserRepository $userRepository;\n\n public function __construct(UserRepository $userRepository)\n {\n $this->userRepository = $userRepository;\n }\n\n public function shouldApplyQueries(): bool\n {\n return count($this->getValue()) > 0;\n }\n\n public function getQueries(): FilterDefinitionQueryCollection\n {\n $userIds = $this->getValue();\n\n return FilterDefinitionQueryCollection::make([\n FilterDefinitionQuery::instance()\n ->setQuery(new Query\\Terms('coachingFeedbacks.coach.id_string', $userIds))\n ->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),\n ]);\n }\n\n public function toArray(): array\n {\n return [\n 'id' => 'coaching-feedback-user-filter',\n 'label' => 'Coach',\n 'helpText' => 'The person who completed the Coaching Framework',\n 'placeholder' => 'Search coaches',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'queryParam' => 'coaching_feedback_coach_id',\n 'options' => $this->getOptions(),\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'value' => $this->getValue(),\n ];\n }\n\n private function getOptions(): array\n {\n $user = $this->executedBy;\n $query = $user\n ->getTeam()\n ->users()\n ->whereNotIn(\n 'uuid',\n $this->userRepository->findInaccessibleDeactivatedUserUuids($user)\n ->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))\n ->all(),\n )\n ->orderBy('name');\n\n $users = $query\n ->with('group')\n ->get()\n ->reduce(\n static function (array $carry, Models\\User $user): array {\n $group = $user->getGroup();\n $groupId = $group !== null\n ? $group->getUuid()\n : self::NO_GROUP_ID;\n $groupName = $group !== null\n ? $group->getName()\n : '(NON-GROUPED)';\n\n if (! array_key_exists($groupId, $carry)) {\n $carry[$groupId] = [\n 'label' => $groupName,\n 'users' => [],\n ];\n }\n\n $carry[$groupId]['users'][] = [\n 'id' => $user->getUuid(),\n 'name' => sprintf(\n '%s%s',\n $user->getName(),\n ! $user->isStatusActive()\n ? ' (Inactive)'\n : ''\n ),\n ];\n\n return $carry;\n },\n []\n );\n\n return Collection::make($users)\n ->sortBy('label')\n ->values()\n ->toArray();\n }\n\n public function getValue(): array\n {\n if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {\n return $this->getDefaultValue();\n }\n\n return array_diff(\n $this->criteria->getCoachingFeedbackCoachUserId(),\n $this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),\n );\n }\n\n private function getDefaultValue(): array\n {\n return [];\n }\n\n public function getValidationRules(?string $prefix = null): array\n {\n $team = $this->executedBy->getTeam();\n\n return [\n $prefix . 'coaching_feedback_coach_id' => 'array',\n $prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),\n ];\n }\n\n public function getSortOrder(): int\n {\n return 86;\n }\n\n public function shouldBeIncluded(Team $team): bool\n {\n return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4316251472625321264
|
-259430402414309411
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Activity;
use ChaseConey\LaravelDatadogHelper\Datadog;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Jiminny\Component\Queue\Constants;
use Jiminny\Component\Sentry\SentryClient;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Contracts\Services\ImportsDataInterface;
use Jiminny\DTO\Activity\Import\ActivityImportResult;
use Jiminny\Exceptions\ActivityProviderException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity\ActivityImport;
use Jiminny\Models\Activity\Provider;
use Jiminny\Services\Activity\ActivityProviderRegistry;
use Jiminny\Services\Import\ActivityImportManager;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use Throwable;
class SyncActivity extends Job implements ShouldQueue
{
use InteractsWithQueue;
use SerializesModels;
public const string ALLOWED_DATE_FORMAT = 'Y-m-d H:i:s';
public int $tries = 3;
public $queue = Constants::QUEUE_DIALERS;
private ActivityImport $import;
private ?ActivityImportManager $activityImportManager = null;
private ?UserRepository $userRepository = null;
private ?SentryClient $sentryClient = null;
private ?LoggerInterface $logger = null;
private ?Provider $provider = null;
private ?ImportsDataInterface $service = null;
private array $context;
public function __construct(ActivityImport $import)
{
$this->import = $import;
$this->context = ['import_id' => $import->getId()];
}
public function handle(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
try {
$this->init(
$activityImportManager,
$activityProviderRegistry,
$userRepository,
$sentry,
$logger,
);
} catch (Throwable $exception) {
$this->failImport($exception);
return;
}
Datadog::increment('jiminny.activity.sync.start', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
try {
$result = $this->run();
$this->complete($result);
} catch (Throwable $exception) {
$this->failImport($exception);
}
}
public function failed(Throwable $exception): void
{
$this->logger ??= app(LoggerInterface::class);
$this->activityImportManager ??= app(ActivityImportManager::class);
$this->sentryClient ??= app(SentryClient::class);
if (! isset($this->context)) {
// This can happen in case of improper deserialization.
$this->context = [];
}
$this->context['team'] ??= 'unknown';
$this->context['provider'] ??= 'unknown';
if (isset($this->import)) {
// This can happen in case of improper deserialization.
$this->failImport($exception);
}
}
/**
* @throws ActivityProviderException
* @throws SocialAccountTokenInvalidException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function init(
ActivityImportManager $activityImportManager,
ActivityProviderRegistry $activityProviderRegistry,
UserRepository $userRepository,
SentryClient $sentry,
LoggerInterface $logger,
): void {
$this->logger = $logger;
$this->activityImportManager = $activityImportManager;
$this->userRepository = $userRepository;
$this->sentryClient = $sentry;
$provider = $this->import->getActivityProvider();
$this->context['provider'] = $provider->getProviderSlug();
$this->context['provider_id'] = $provider->getId();
$this->context['team'] = $provider->getTeam()->getSlug();
$this->context['team_id'] = $provider->getTeamId();
if (! $provider->isEnabled()) {
throw new ActivityProviderException('Activity provider is disabled', $provider);
}
$this->provider = $provider;
$service = $activityProviderRegistry->get($provider->getProviderSlug());
if (! $service instanceof ImportsDataInterface) {
throw new ActivityProviderException('Activity provider does not support data imports', $provider);
}
$service->setTeam($provider->getTeam());
$service->setSocialAccount($provider->getConnectedSocialAccount());
$service->setDebug($this->import->runsInDebug());
$this->service = $service;
}
private function run(): ActivityImportResult
{
$this->logger->info('[SyncActivity] Start', $this->context);
$this->activityImportManager->start($this->import);
$importedRecords = $this->service->importData(
$this->import->getStartDate(),
$this->import->getEndDate(),
$this->userRepository->findOneBy(['id' => $this->import->getUserId()]),
$this->import->getActivityId()
);
return (new ActivityImportResult())
->setTotal($importedRecords)
->addImported($importedRecords)
;
}
private function complete(ActivityImportResult $result): void
{
$this->activityImportManager->complete($this->import, $result);
Datadog::increment('jiminny.activity.sync.success', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
]);
$this->logger->info('[SyncActivity] End', $this->context);
$this->logger->info(
'[SyncActivity] Memory usage',
array_merge(
$this->context,
[
'memory_usage' => memory_get_usage(),
'memory_real_usage' => memory_get_usage(true),
'pid' => getmypid(),
],
),
);
}
private function failImport(Throwable $exception): void
{
$this->logger->alert(
message: '[SyncActivity] Failed',
context: array_merge($this->context, [
'reason' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
]),
);
$this->activityImportManager->fail($this->import);
Datadog::increment('jiminny.activity.sync.exception', 1.0, [
'company' => $this->context['team'],
'provider' => $this->context['provider'],
'exception' => $exception::class,
'exceptionCode' => $exception->getCode(),
]);
if ($exception instanceof SocialAccountTokenInvalidException) {
return;
}
$this->sentryClient->captureException($exception);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\ActivitySearch\FilterDefinition;
use Illuminate\Support\Collection;
use Jiminny\Component\ActivitySearch\FilterDefinition;
use Jiminny\Component\ActivitySearch\FilterDefinitionQuery;
use Jiminny\Component\ActivitySearch\FilterDefinitionQueryCollection;
use Jiminny\Contracts\ActivitySearch\ValidatedFilterDefinitionInterface;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Models;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Team;
use Jiminny\Traits\RequiresUUID;
use Elastica\Query;
final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface
{
private const int NO_GROUP_ID = 999;
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function shouldApplyQueries(): bool
{
return count($this->getValue()) > 0;
}
public function getQueries(): FilterDefinitionQueryCollection
{
$userIds = $this->getValue();
return FilterDefinitionQueryCollection::make([
FilterDefinitionQuery::instance()
->setQuery(new Query\Terms('coachingFeedbacks.coach.id_string', $userIds))
->setPath('coachingFeedbacks.coach', 'coachingFeedbacks'),
]);
}
public function toArray(): array
{
return [
'id' => 'coaching-feedback-user-filter',
'label' => 'Coach',
'helpText' => 'The person who completed the Coaching Framework',
'placeholder' => 'Search coaches',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'queryParam' => 'coaching_feedback_coach_id',
'options' => $this->getOptions(),
'groupLabelKey' => 'label',
'groupValuesKey' => 'users',
'optionLabelKey' => 'name',
'optionValueKey' => 'id',
'value' => $this->getValue(),
];
}
private function getOptions(): array
{
$user = $this->executedBy;
$query = $user
->getTeam()
->users()
->whereNotIn(
'uuid',
$this->userRepository->findInaccessibleDeactivatedUserUuids($user)
->map(static fn (string $uuid): string => RequiresUUID::toOptimized($uuid))
->all(),
)
->orderBy('name');
$users = $query
->with('group')
->get()
->reduce(
static function (array $carry, Models\User $user): array {
$group = $user->getGroup();
$groupId = $group !== null
? $group->getUuid()
: self::NO_GROUP_ID;
$groupName = $group !== null
? $group->getName()
: '(NON-GROUPED)';
if (! array_key_exists($groupId, $carry)) {
$carry[$groupId] = [
'label' => $groupName,
'users' => [],
];
}
$carry[$groupId]['users'][] = [
'id' => $user->getUuid(),
'name' => sprintf(
'%s%s',
$user->getName(),
! $user->isStatusActive()
? ' (Inactive)'
: ''
),
];
return $carry;
},
[]
);
return Collection::make($users)
->sortBy('label')
->values()
->toArray();
}
public function getValue(): array
{
if (! $this->criteria->hasCoachingFeedbackCoachUserIds()) {
return $this->getDefaultValue();
}
return array_diff(
$this->criteria->getCoachingFeedbackCoachUserId(),
$this->userRepository->findInaccessibleDeactivatedUserUuids($this->executedBy)->all(),
);
}
private function getDefaultValue(): array
{
return [];
}
public function getValidationRules(?string $prefix = null): array
{
$team = $this->executedBy->getTeam();
return [
$prefix . 'coaching_feedback_coach_id' => 'array',
$prefix . 'coaching_feedback_coach_id.*' => 'uuid:users,team_id,' . $team->getId(),
];
}
public function getSortOrder(): int
{
return 86;
}
public function shouldBeIncluded(Team $team): bool
{
return $team->hasFeature(FeatureEnum::COACHING_FRAMEWORK);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
56123
|
NULL
|
NULL
|
NULL
|
|
56122
|
NULL
|
0
|
2026-05-19T07:27:29.207697+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175649207_m1.jpg...
|
PhpStorm
|
Tip of the Day
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Quick code documentation
To quickly see the docume Quick code documentation
To quickly see the documentation for a class or method at the caret, press ⇧ ⌘ P → Quick Documentation (View | Quick Documentation).
Did you find this tip useful?
Like
Dislike
Don't show tips on startup
Close
Back
Next
Tip of the Day...
|
[{"role":"AXTextField","text [{"role":"AXTextField","text":"Quick code documentation\nTo quickly see the documentation for a class or method at the caret, press ⇧ ⌘ P → Quick Documentation (View | Quick Documentation).","depth":2,"on_screen":true,"value":"Quick code documentation\nTo quickly see the documentation for a class or method at the caret, press ⇧ ⌘ P → Quick Documentation (View | Quick Documentation).","help_text":"text/plain","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Did you find this tip useful?","depth":1,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Like","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dislike","depth":2,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Don't show tips on startup","depth":1,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Back","depth":1,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next","depth":1,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tip of the Day","depth":1,"on_screen":true,"role_description":"text"}]...
|
5876713665850453483
|
-7829190541826070826
|
click
|
accessibility
|
NULL
|
Quick code documentation
To quickly see the docume Quick code documentation
To quickly see the documentation for a class or method at the caret, press ⇧ ⌘ P → Quick Documentation (View | Quick Documentation).
Did you find this tip useful?
Like
Dislike
Don't show tips on startup
Close
Back
Next
Tip of the Day...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56091
|
NULL
|
0
|
2026-05-19T07:22:01.090746+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175321090_m2.jpg...
|
Firefox
|
Помогнете ни да развиваме My Vivacom – Вашето мнен Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - kovaliklukas@gmail.com - Gmail — Personal...
|
1
|
mail.google.com/mail/u/0/#inbox/FMfcgzQgLrxWFhgMXc mail.google.com/mail/u/0/#inbox/FMfcgzQgLrxWFhgMXcshjNcVcGZfSgSJ...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started · AFFiNE
Getting Started · AFFiNE
Screenpipe — Archive
Screenpipe — Archive
Download screenpipe — get started in minutes
Download screenpipe — get started in minutes
Self-Hosted Software and Apps
Self-Hosted Software and Apps
New Tab
New Tab
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - [EMAIL] - Gmail
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - [EMAIL] - Gmail
Close tab
Завеждане на щета онлайн | Euroins
Завеждане на щета онлайн | Euroins
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Nginx Proxy Manager
Nginx Proxy Manager
Location Logger
Location Logger
Providers - Admin - authentik
Providers - Admin - authentik
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])
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 8 unread
Drafts
8
Purchases has menu
Purchases
Social 5219 unread has menu
Social
5,219
Updates 8821 unread has menu
Updates
8,821
Forums 6150 unread has menu
Forums
6,150
Promotions 38834 unread has menu
Promotions
38,834
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 7547 unread has menu
jiminny-github
7,547
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
Back to Inbox
Archive
Report spam
Delete
Mark as unread
Move to
More email options
1
of
21,316
Newer
Older
Input tools on/off (Ctrl-Shift-K)
Select input tool
Print all
In new window
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно
Important according to Google magic
Search for all messages with label Inbox
Remove label Inbox from this conversation
Vivacom [EMAIL] Unsubscribe
Vivacom [EMAIL]
Vivacom
[EMAIL]
Unsubscribe
Unsubscribe
10:13 (8 minutes ago)
10:13 (8 minutes ago)
Not starred
You can't react to a group with an emoji
Reply
More message options
to
me
Show details
It looks like this message is in Bulgarian
Translate to English
Translate to English
Dismiss
За отписване от бюлетина натиснете
тук
тук
.
Reply
Reply
Forward
Forward
You can't react to a group with an emoji
Calendar
Keep
Tasks
Contacts
Get add-ons
Hide side panel...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.5,"top":0.0518755,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.51329786,"top":0.06304868,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Getting Started · AFFiNE","depth":4,"bounds":{"left":0.5,"top":0.08459697,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Getting Started · AFFiNE","depth":5,"bounds":{"left":0.51329786,"top":0.09577015,"width":0.04255319,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.11731844,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.51329786,"top":0.12849163,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Download screenpipe — get started in minutes","depth":4,"bounds":{"left":0.5,"top":0.15003991,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download screenpipe — get started in minutes","depth":5,"bounds":{"left":0.51329786,"top":0.16121309,"width":0.0809508,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Self-Hosted Software and Apps","depth":4,"bounds":{"left":0.5,"top":0.18276137,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Self-Hosted Software and Apps","depth":5,"bounds":{"left":0.51329786,"top":0.19393456,"width":0.054853722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.21548285,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.51329786,"top":0.22665602,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.5,"top":0.2482043,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.51329786,"top":0.25937748,"width":0.18118352,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.55651593,"top":0.25538707,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Завеждане на щета онлайн | Euroins","depth":4,"bounds":{"left":0.5,"top":0.28092578,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Завеждане на щета онлайн | Euroins","depth":5,"bounds":{"left":0.51329786,"top":0.29209897,"width":0.0653258,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii","depth":4,"bounds":{"left":0.5,"top":0.31364724,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii","depth":5,"bounds":{"left":0.51329786,"top":0.32482043,"width":0.091090426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.5,"top":0.3463687,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.51329786,"top":0.3575419,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.5,"top":0.3790902,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.51329786,"top":0.39026338,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Providers - Admin - authentik","depth":4,"bounds":{"left":0.5,"top":0.41181165,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers - Admin - authentik","depth":5,"bounds":{"left":0.51329786,"top":0.42298484,"width":0.05119681,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.5028258,"top":0.4461293,"width":0.06333112,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.5028258,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.51379657,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.5249335,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.53607047,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.5472075,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"None selected","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using Gmail with screen readers","depth":10,"on_screen":false,"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,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Main menu","depth":11,"bounds":{"left":0.5728058,"top":0.058260176,"width":0.015957447,"height":0.03830806},"on_screen":true,"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.5900931,"top":0.061452515,"width":0.036236703,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Search","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search mail","depth":18,"bounds":{"left":0.6722075,"top":0.06943336,"width":0.18916224,"height":0.016360734},"on_screen":true,"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.8746675,"top":0.058260176,"width":0.01861702,"height":0.03671189},"on_screen":true,"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.65392286,"top":0.058260176,"width":0.01861702,"height":0.03671189},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Support","depth":12,"bounds":{"left":0.92353725,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Settings","depth":12,"bounds":{"left":0.9381649,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Ask Gemini","depth":12,"bounds":{"left":0.95212764,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"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},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":14,"bounds":{"left":0.98204786,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compose","depth":9,"bounds":{"left":0.57147604,"top":0.10933759,"width":0.04737367,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox","depth":16,"bounds":{"left":0.5900931,"top":0.15003991,"width":0.012466756,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.15003991,"width":0.012466756,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Starred","depth":17,"bounds":{"left":0.5900931,"top":0.16919394,"width":0.015625,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.16919394,"width":0.015625,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Snoozed","depth":17,"bounds":{"left":0.5900931,"top":0.18834797,"width":0.018284574,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.18834797,"width":0.018284574,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Important","depth":17,"bounds":{"left":0.5900931,"top":0.207502,"width":0.020777926,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.207502,"width":0.020777926,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent","depth":17,"bounds":{"left":0.5900931,"top":0.22665602,"width":0.009640957,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.22665602,"width":0.009640957,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Drafts 8 unread","depth":17,"bounds":{"left":0.5900931,"top":0.24581006,"width":0.013796543,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.24581006,"width":0.013796543,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":17,"bounds":{"left":0.6437833,"top":0.24700718,"width":0.0021609042,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Purchases has menu","depth":16,"bounds":{"left":0.5900931,"top":0.26496407,"width":0.021941489,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.26496407,"width":0.021941489,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Social 5219 unread has menu","depth":16,"bounds":{"left":0.5900931,"top":0.28411812,"width":0.013796543,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.28411812,"width":0.013796543,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5,219","depth":16,"bounds":{"left":0.63663566,"top":0.28531525,"width":0.00930851,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Updates 8821 unread has menu","depth":16,"bounds":{"left":0.5900931,"top":0.30327216,"width":0.018949468,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.30327216,"width":0.018949468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8,821","depth":16,"bounds":{"left":0.63680184,"top":0.3044693,"width":0.009142287,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums 6150 unread has menu","depth":16,"bounds":{"left":0.5900931,"top":0.32242617,"width":0.016788565,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.32242617,"width":0.016788565,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6,150","depth":16,"bounds":{"left":0.6363032,"top":0.3236233,"width":0.009640957,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Promotions 38834 unread has menu","depth":16,"bounds":{"left":0.5900931,"top":0.3415802,"width":0.025930852,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.3415802,"width":0.025930852,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38,834","depth":16,"bounds":{"left":0.63397604,"top":0.34277734,"width":0.011968086,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"bounds":{"left":0.5688165,"top":0.35834,"width":0.07978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.5900931,"top":0.36073422,"width":0.010804521,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Labels","depth":11,"bounds":{"left":0.5774601,"top":0.39984038,"width":0.061835106,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":12,"bounds":{"left":0.5774601,"top":0.39984038,"width":0.016456118,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create new label","depth":11,"bounds":{"left":0.6392952,"top":0.40023944,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[Imap]/Nevyžiadaná pošta has menu","depth":17,"bounds":{"left":0.5900931,"top":0.42817238,"width":0.055352394,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.42817238,"width":0.055352394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"arch has menu","depth":17,"bounds":{"left":0.5900931,"top":0.44732642,"width":0.009474734,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.44732642,"width":0.009474734,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deleted Items has menu","depth":17,"bounds":{"left":0.5900931,"top":0.46648043,"width":0.029089095,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.46648043,"width":0.029089095,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fibank 1229 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.48563448,"width":0.01512633,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.48563448,"width":0.01512633,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,229","depth":17,"bounds":{"left":0.63680184,"top":0.4868316,"width":0.009142287,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"FL 6 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.5047885,"width":0.005319149,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.5047885,"width":0.005319149,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":17,"bounds":{"left":0.64361703,"top":0.5059856,"width":0.0023271276,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Hardware & Software has menu","depth":17,"bounds":{"left":0.5900931,"top":0.52394253,"width":0.044714097,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.52394253,"width":0.044714097,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HOSTING 5 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.54309654,"width":0.02144282,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.54309654,"width":0.02144282,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":17,"bounds":{"left":0.6437833,"top":0.5442937,"width":0.0021609042,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Infected Items has menu","depth":17,"bounds":{"left":0.5900931,"top":0.5622506,"width":0.030086435,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.5622506,"width":0.030086435,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"jiminny-github 7547 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.5814046,"width":0.03324468,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.5814046,"width":0.03324468,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7,547","depth":17,"bounds":{"left":0.63680184,"top":0.5826017,"width":0.009142287,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Junk E-mail 219 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.60055864,"width":0.026761968,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.60055864,"width":0.026761968,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"219","depth":17,"bounds":{"left":0.6399601,"top":0.6017558,"width":0.005984043,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Kontakty has menu","depth":17,"bounds":{"left":0.5900931,"top":0.6197127,"width":0.018450798,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.6197127,"width":0.018450798,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent Items has menu","depth":17,"bounds":{"left":0.5900931,"top":0.6388667,"width":0.022273935,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.6388667,"width":0.022273935,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"WORK 848 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.65802073,"width":0.014461436,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.65802073,"width":0.014461436,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"848","depth":17,"bounds":{"left":0.6392952,"top":0.6592179,"width":0.0066489363,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"z centra 1274 unread has menu","depth":17,"bounds":{"left":0.5900931,"top":0.6771748,"width":0.018118352,"height":0.014764565},"on_screen":true,"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.5900931,"top":0.6771748,"width":0.018118352,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,274","depth":17,"bounds":{"left":0.6371343,"top":0.6783719,"width":0.00880984,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"bounds":{"left":0.5688165,"top":0.69393456,"width":0.07978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.5900931,"top":0.6963288,"width":0.010804521,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Back to Inbox","depth":11,"bounds":{"left":0.65924203,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Archive","depth":11,"bounds":{"left":0.67785907,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Report spam","depth":11,"bounds":{"left":0.6924867,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Delete","depth":11,"bounds":{"left":0.70711434,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Mark as unread","depth":11,"bounds":{"left":0.72706115,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Move to","depth":11,"bounds":{"left":0.74168885,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More email options","depth":11,"bounds":{"left":0.7549867,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"More","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":11,"bounds":{"left":0.90724736,"top":0.11612131,"width":0.0016622341,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"of","depth":11,"bounds":{"left":0.90890956,"top":0.11612131,"width":0.005817819,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21,316","depth":11,"bounds":{"left":0.9147274,"top":0.11612131,"width":0.010804521,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Newer","depth":10,"bounds":{"left":0.9321808,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Older","depth":10,"bounds":{"left":0.94547874,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"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":11,"bounds":{"left":0.9574468,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Select input tool","depth":11,"bounds":{"left":0.9640958,"top":0.11412609,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Print all","depth":13,"bounds":{"left":0.95412236,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"In new window","depth":13,"bounds":{"left":0.96609044,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Помогнете ни да развиваме My Vivacom – Вашето мнение е важно","depth":13,"bounds":{"left":0.67785907,"top":0.0,"width":0.2322141,"height":0.022346368},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Помогнете ни да развиваме My Vivacom – Вашето мнение е важно","depth":14,"bounds":{"left":0.67785907,"top":0.0,"width":0.22888963,"height":0.022346368},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Important according to Google magic","depth":14,"bounds":{"left":0.90674865,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search for all messages with label Inbox","depth":15,"bounds":{"left":0.92004657,"top":0.0,"width":0.011801862,"height":0.014365523},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Remove label Inbox from this conversation","depth":15,"bounds":{"left":0.9318484,"top":0.0,"width":0.004986702,"height":0.014365523},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Vivacom Anketa@my.vivacom.bg Unsubscribe","depth":23,"bounds":{"left":0.67785907,"top":0.021548284,"width":0.105884306,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXCell","text":"Vivacom Anketa@my.vivacom.bg","depth":24,"bounds":{"left":0.67785907,"top":0.023543496,"width":0.06781915,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Vivacom","depth":25,"bounds":{"left":0.67785907,"top":0.022346368,"width":0.019281914,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Anketa@my.vivacom.bg","depth":25,"bounds":{"left":0.7002992,"top":0.023543496,"width":0.042386968,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Unsubscribe","depth":25,"bounds":{"left":0.74833775,"top":0.021548284,"width":0.035405584,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unsubscribe","depth":26,"bounds":{"left":0.75232714,"top":0.022346368,"width":0.027426861,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCell","text":"10:13 (8 minutes ago)","depth":20,"bounds":{"left":0.88447475,"top":0.021548284,"width":0.038397606,"height":0.015961692},"on_screen":true,"help_text":"19 May 2026, 10:13","role_description":"cell","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:13 (8 minutes ago)","depth":21,"bounds":{"left":0.88447475,"top":0.023543496,"width":0.038397606,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not starred","depth":21,"bounds":{"left":0.92952126,"top":0.021548284,"width":0.0066489363,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"You can't react to a group with an emoji","depth":21,"bounds":{"left":0.93949467,"top":0.013567438,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Reply","depth":21,"bounds":{"left":0.9527925,"top":0.013567438,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More message options","depth":22,"bounds":{"left":0.96609044,"top":0.013567438,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"to","depth":24,"bounds":{"left":0.67785907,"top":0.039505187,"width":0.004654255,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"me","depth":24,"bounds":{"left":0.6825133,"top":0.039505187,"width":0.0056515955,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Show details","depth":23,"bounds":{"left":0.68949467,"top":0.040702313,"width":0.0039893617,"height":0.009577015},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"It looks like this message is in Bulgarian","depth":21,"bounds":{"left":0.6938165,"top":0.07182761,"width":0.09840426,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Translate to English","depth":21,"bounds":{"left":0.6911569,"top":0.09377494,"width":0.04338431,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Translate to English","depth":23,"bounds":{"left":0.6938165,"top":0.09377494,"width":0.038065158,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss","depth":20,"bounds":{"left":0.80019945,"top":0.06304868,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"За отписване от бюлетина натиснете","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"тук","depth":22,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"тук","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":22,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Reply","depth":14,"bounds":{"left":0.67785907,"top":0.773344,"width":0.034574468,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Reply","depth":15,"bounds":{"left":0.69298536,"top":0.78052676,"width":0.012300532,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forward","depth":14,"bounds":{"left":0.7150931,"top":0.773344,"width":0.03723404,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forward","depth":15,"bounds":{"left":0.7287234,"top":0.78052676,"width":0.017952127,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"You can't react to a group with an emoji","depth":15,"bounds":{"left":0.7549867,"top":0.773344,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Calendar","depth":10,"bounds":{"left":0.98138297,"top":0.10295291,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Keep","depth":10,"bounds":{"left":0.98138297,"top":0.14764565,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Tasks","depth":10,"bounds":{"left":0.98138297,"top":0.19233839,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Contacts","depth":10,"bounds":{"left":0.98138297,"top":0.23703113,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Get add-ons","depth":10,"bounds":{"left":0.98138297,"top":0.30806065,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Hide side panel","depth":9,"bounds":{"left":0.98138297,"top":0.95530725,"width":0.01861702,"height":0.044692736},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3827621655080102668
|
-111186951262313539
|
visual_change
|
accessibility
|
NULL
|
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started · AFFiNE
Getting Started · AFFiNE
Screenpipe — Archive
Screenpipe — Archive
Download screenpipe — get started in minutes
Download screenpipe — get started in minutes
Self-Hosted Software and Apps
Self-Hosted Software and Apps
New Tab
New Tab
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - [EMAIL] - Gmail
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно - [EMAIL] - Gmail
Close tab
Завеждане на щета онлайн | Euroins
Завеждане на щета онлайн | Euroins
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Nginx Proxy Manager
Nginx Proxy Manager
Location Logger
Location Logger
Providers - Admin - authentik
Providers - Admin - authentik
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])
Compose
Labels
Labels
Inbox
Inbox
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 8 unread
Drafts
8
Purchases has menu
Purchases
Social 5219 unread has menu
Social
5,219
Updates 8821 unread has menu
Updates
8,821
Forums 6150 unread has menu
Forums
6,150
Promotions 38834 unread has menu
Promotions
38,834
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 7547 unread has menu
jiminny-github
7,547
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
Back to Inbox
Archive
Report spam
Delete
Mark as unread
Move to
More email options
1
of
21,316
Newer
Older
Input tools on/off (Ctrl-Shift-K)
Select input tool
Print all
In new window
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно
Помогнете ни да развиваме My Vivacom – Вашето мнение е важно
Important according to Google magic
Search for all messages with label Inbox
Remove label Inbox from this conversation
Vivacom [EMAIL] Unsubscribe
Vivacom [EMAIL]
Vivacom
[EMAIL]
Unsubscribe
Unsubscribe
10:13 (8 minutes ago)
10:13 (8 minutes ago)
Not starred
You can't react to a group with an emoji
Reply
More message options
to
me
Show details
It looks like this message is in Bulgarian
Translate to English
Translate to English
Dismiss
За отписване от бюлетина натиснете
тук
тук
.
Reply
Reply
Forward
Forward
You can't react to a group with an emoji
Calendar
Keep
Tasks
Contacts
Get add-ons
Hide side panel...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
56089
|
NULL
|
0
|
2026-05-19T07:21:56.318894+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175316318_m1.jpg...
|
Firefox
|
Inbox (1) - kovaliklukas@gmail.com - Gmail — Perso Inbox (1) - kovaliklukas@gmail.com - Gmail — Personal...
|
1
|
mail.google.com/mail/u/0/#inbox
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Завеждане на щета онлайн | Euroins
euroins.bg
DXP4 Завеждане на щета онлайн | Euroins
euroins.bg
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started · AFFiNE
Getting Started · AFFiNE
Screenpipe — Archive
Screenpipe — Archive
Download screenpipe — get started in minutes
Download screenpipe — get started in minutes
Self-Hosted Software and Apps
Self-Hosted Software and Apps
New Tab
New Tab
Inbox (1) - [EMAIL] - Gmail
Inbox (1) - [EMAIL] - Gmail
Close tab
Завеждане на щета онлайн | Euroins
Завеждане на щета онлайн | Euroins
Close tab
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Nginx Proxy Manager
Nginx Proxy Manager
Location Logger
Location Logger
Providers - Admin - authentik
Providers - Admin - authentik
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])
Compose
Labels
Labels
Inbox 1 unread
Inbox
1
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 8 unread
Drafts
8
Purchases has menu
Purchases
Social 5219 unread has menu
Social
5,219
Updates 8822 unread has menu
Updates
8,822
Forums 6150 unread has menu
Forums
6,150
Promotions 38834 unread has menu
Promotions
38,834
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...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Завеждане на щета онлайн | Euroins","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"euroins.bg","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Getting Started · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Getting Started · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Download screenpipe — get started in minutes","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Download screenpipe — get started in minutes","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Self-Hosted Software and Apps","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Self-Hosted Software and Apps","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox (1) - kovaliklukas@gmail.com - Gmail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Inbox (1) - kovaliklukas@gmail.com - Gmail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Завеждане на щета онлайн | Euroins","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Завеждане на щета онлайн | Euroins","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Providers - Admin - authentik","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Providers - Admin - authentik","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.48576388,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.5086806,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.53194445,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.5552083,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"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.5784722,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"None selected","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Using Gmail with screen readers","depth":10,"on_screen":false,"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,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Main menu","depth":11,"on_screen":true,"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,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Search","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Search","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search mail","depth":18,"on_screen":true,"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,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search mail","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Support","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Ask Gemini","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Google apps","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Google Account: Lukáš Koválik (kovaliklukas@gmail.com)","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compose","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Inbox 1 unread","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Starred","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Starred","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Snoozed","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Snoozed","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Important","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Important","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sent","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sent","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Drafts 8 unread","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Drafts","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Purchases has menu","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Purchases","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Social 5219 unread has menu","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Social","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5,219","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Updates 8822 unread has menu","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Updates","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8,822","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Forums 6150 unread has menu","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Forums","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6,150","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Promotions 38834 unread has menu","depth":16,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Promotions","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"38,834","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More labels","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Labels","depth":11,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create new label","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Labels","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Labels","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"[Imap]/Nevyžiadaná pošta has menu","depth":17,"on_screen":true,"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,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"arch has menu","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"arch","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deleted Items has menu","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deleted Items","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Fibank 1229 unread has menu","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fibank","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1,229","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"FL 6 unread has menu","depth":17,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"FL","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-1797153731186764134
|
-3970769233463612753
|
click
|
accessibility
|
NULL
|
Завеждане на щета онлайн | Euroins
euroins.bg
DXP4 Завеждане на щета онлайн | Euroins
euroins.bg
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Getting Started · AFFiNE
Getting Started · AFFiNE
Screenpipe — Archive
Screenpipe — Archive
Download screenpipe — get started in minutes
Download screenpipe — get started in minutes
Self-Hosted Software and Apps
Self-Hosted Software and Apps
New Tab
New Tab
Inbox (1) - [EMAIL] - Gmail
Inbox (1) - [EMAIL] - Gmail
Close tab
Завеждане на щета онлайн | Euroins
Завеждане на щета онлайн | Euroins
Close tab
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Kontakt | Veľvyslanectvo Slovenskej republiky v Sofii
Nginx Proxy Manager
Nginx Proxy Manager
Location Logger
Location Logger
Providers - Admin - authentik
Providers - Admin - authentik
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])
Compose
Labels
Labels
Inbox 1 unread
Inbox
1
Starred
Starred
Snoozed
Snoozed
Important
Important
Sent
Sent
Drafts 8 unread
Drafts
8
Purchases has menu
Purchases
Social 5219 unread has menu
Social
5,219
Updates 8822 unread has menu
Updates
8,822
Forums 6150 unread has menu
Forums
6,150
Promotions 38834 unread has menu
Promotions
38,834
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...
|
56087
|
NULL
|
NULL
|
NULL
|
|
56049
|
NULL
|
0
|
2026-05-19T07:17:09.905716+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175029905_m2.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Notion CalendarVIewravourtes• jiminny© RecentsA, A Notion CalendarVIewravourtes• jiminny© RecentsA, Applications|9 Document• Downloadsin lukasiCloud• iCloud Drive992 Svnc tolde0 DXP4800PLUS-B5F A49 Network• CRM• Orange• Red• Yellov• Greer• Blue• Purple• All Tags.WindowmeltScripisApplicationscascaderrojectscleansnot-live..logcleanshot-screenpipe.log• clip.mp4DesktopDEVDocumentso Downloadsframe.jpgiCloud Drive (Archive)iminnyKeychron ScreenEMoviesMusicnode modulesPicturesPostmano Publicraycastrecnonce binscreenpipe-day.sh1 Untitled A cofUsersel yarn.lockclipboard-dis...ed-after-crashdalddo.solltedo.sclite-shmdb.scllte-walpipes• prune.locscreenpipe sync.shscreenpipe_sync.sh-bakkscreenpipe_sync.sh.bakscreenpipe_sync.sh.bak2screenpipe.2026-05-06.0.log• screenpipe.2026-05-07.0.loascreenpipe.2026-05-08.0.logI screenpine 2026-05-09.0.100L screenoine 2026-05-10.0.10ala screenpipe.2026-05-11.0.10gE screenoine 2026-05-12.0.100• screenpipe.2026-05-13.0.1ogE screenbine 2026-05-14.0.100• screenpipe.2026-05-15.0.1ogE screpnnine 2026-05-16.0100screenpipe.2026-05-18.0.1ogP screennine 2026-05-19 0 loa.store.birsync.log000 vGroupShare Add Tagslitscreenpipe_prune_mac.sh- screenpipe_revert_db.shscreenpipe_sync.shoo00Q0June 2026Monl.chioe cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andrea Zlatanova (Parental Leave - 189 days)Kara Jones (Unpaid Leave of Absence - 9 davs)Calum Scott (PTO - 2 days)Nick Yankov (PTO - 1 day)09:45 Daily - Platform15:00 support Dallychioe cross (Parental Leave - 256 days)Ivelind hiristova (Parental Leave" 104 days)Andrea Zlatanova (Parental Leave - 189 davs)15:00 Preparation for Refinement09:45 Daily - Platform15:00 support Daily16:00 (Platforml Refinement©15:00 support DallyChioe Cross (Darental I eave - 256 dave)Ivelina Hristova (Parental Leave - 184 davs)Stoyan Tomov (PTO - 4.5 days)09:45 Daily - Platform16:00 Prenaration for Refinement09:45 Daily - Platrorm3 moreChloe Cross (Parental Leave - 256 davs)Andrea Zlatanova (Parental Leave - 189 days)00:/6 Daily- DintformJames Granam (Plo - 4 days)15:00 Support DailvChloe Cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andres Zlatanova (Parental Leave - 189 days)Mario Georaiev (DTO - 6 dave)3 moreChloe Cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andres Zlatanova (Darental Ieave. 180 dave)Stovan Tomov (PTO - 3.5 davs)09:45 Daily - PlatformPlatform Office DayamordWedk09:45 Daily - Platform15:00 Support Dally17:00 Al chapter10:00 Mid Sprint Check-in15:00 support Daily14:00 Sorint Review09:45 Daily - Plattorm15:00 Support Daily10:00 [Platform] Planning I Sessi...2 moreHulv Mornina09:45 Daily - Platform2 moreRebecca Butler (PTO - 8 days)4A more• supoont Dally • In 4n 43 m100% Lz• Tue 19 May 10:17:09Month vTodan15:00 Support Dally17:30 Lukas/Stefka 12'15:00 Support Daily09:45 Daily - Plattorm15:00 Support Daily10:00 Jiminny Tech Day10:30 Backend Chapter09:45 Daily - Platrorm15:00 Support Daily17:30 Lukas/Stefka 12'Stefka Stoyanova (PTO - 1 day)00:26 Daily - Dlatforn15:00 Support DailvMario Georaiev (PTO - 6 davs)09:45 Daily - PlatformGeorai Bavraktarov (PTO - 0,5 d...Sviatok suätáho Curila a MetodaGeorai Bavraktarov (PTO - 1.5 dav)2 more09:45 Daily - Platforn15:00 Support Daily1 09:45 Daily - Platform09:45 Daily - Platform...
|
NULL
|
-7240967564667362974
|
NULL
|
idle
|
ocr
|
NULL
|
Notion CalendarVIewravourtes• jiminny© RecentsA, A Notion CalendarVIewravourtes• jiminny© RecentsA, Applications|9 Document• Downloadsin lukasiCloud• iCloud Drive992 Svnc tolde0 DXP4800PLUS-B5F A49 Network• CRM• Orange• Red• Yellov• Greer• Blue• Purple• All Tags.WindowmeltScripisApplicationscascaderrojectscleansnot-live..logcleanshot-screenpipe.log• clip.mp4DesktopDEVDocumentso Downloadsframe.jpgiCloud Drive (Archive)iminnyKeychron ScreenEMoviesMusicnode modulesPicturesPostmano Publicraycastrecnonce binscreenpipe-day.sh1 Untitled A cofUsersel yarn.lockclipboard-dis...ed-after-crashdalddo.solltedo.sclite-shmdb.scllte-walpipes• prune.locscreenpipe sync.shscreenpipe_sync.sh-bakkscreenpipe_sync.sh.bakscreenpipe_sync.sh.bak2screenpipe.2026-05-06.0.log• screenpipe.2026-05-07.0.loascreenpipe.2026-05-08.0.logI screenpine 2026-05-09.0.100L screenoine 2026-05-10.0.10ala screenpipe.2026-05-11.0.10gE screenoine 2026-05-12.0.100• screenpipe.2026-05-13.0.1ogE screenbine 2026-05-14.0.100• screenpipe.2026-05-15.0.1ogE screpnnine 2026-05-16.0100screenpipe.2026-05-18.0.1ogP screennine 2026-05-19 0 loa.store.birsync.log000 vGroupShare Add Tagslitscreenpipe_prune_mac.sh- screenpipe_revert_db.shscreenpipe_sync.shoo00Q0June 2026Monl.chioe cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andrea Zlatanova (Parental Leave - 189 days)Kara Jones (Unpaid Leave of Absence - 9 davs)Calum Scott (PTO - 2 days)Nick Yankov (PTO - 1 day)09:45 Daily - Platform15:00 support Dallychioe cross (Parental Leave - 256 days)Ivelind hiristova (Parental Leave" 104 days)Andrea Zlatanova (Parental Leave - 189 davs)15:00 Preparation for Refinement09:45 Daily - Platform15:00 support Daily16:00 (Platforml Refinement©15:00 support DallyChioe Cross (Darental I eave - 256 dave)Ivelina Hristova (Parental Leave - 184 davs)Stoyan Tomov (PTO - 4.5 days)09:45 Daily - Platform16:00 Prenaration for Refinement09:45 Daily - Platrorm3 moreChloe Cross (Parental Leave - 256 davs)Andrea Zlatanova (Parental Leave - 189 days)00:/6 Daily- DintformJames Granam (Plo - 4 days)15:00 Support DailvChloe Cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andres Zlatanova (Parental Leave - 189 days)Mario Georaiev (DTO - 6 dave)3 moreChloe Cross (Parental Leave - 256 days)Ivelina Hristova (Parental Leave - 184 days)Andres Zlatanova (Darental Ieave. 180 dave)Stovan Tomov (PTO - 3.5 davs)09:45 Daily - PlatformPlatform Office DayamordWedk09:45 Daily - Platform15:00 Support Dally17:00 Al chapter10:00 Mid Sprint Check-in15:00 support Daily14:00 Sorint Review09:45 Daily - Plattorm15:00 Support Daily10:00 [Platform] Planning I Sessi...2 moreHulv Mornina09:45 Daily - Platform2 moreRebecca Butler (PTO - 8 days)4A more• supoont Dally • In 4n 43 m100% Lz• Tue 19 May 10:17:09Month vTodan15:00 Support Dally17:30 Lukas/Stefka 12'15:00 Support Daily09:45 Daily - Plattorm15:00 Support Daily10:00 Jiminny Tech Day10:30 Backend Chapter09:45 Daily - Platrorm15:00 Support Daily17:30 Lukas/Stefka 12'Stefka Stoyanova (PTO - 1 day)00:26 Daily - Dlatforn15:00 Support DailvMario Georaiev (PTO - 6 davs)09:45 Daily - PlatformGeorai Bavraktarov (PTO - 0,5 d...Sviatok suätáho Curila a MetodaGeorai Bavraktarov (PTO - 1.5 dav)2 more09:45 Daily - Platforn15:00 Support Daily1 09:45 Daily - Platform09:45 Daily - Platform...
|
56047
|
NULL
|
NULL
|
NULL
|
|
56048
|
NULL
|
0
|
2026-05-19T07:16:57.186366+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779175017186_m1.jpg...
|
Firefox
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
QuickTime PlayerFileEditViewWindowHelp• Support Da QuickTime PlayerFileEditViewWindowHelp• Support Daily • in 4 h 44 m100% C78• Tue 19 May 10:16:56-zshAPP (-zsh)DOCKERO ₴1DEV (-zsh)₴82*3screenpipe"0 ₴4-zsh=>[api internal] load builddefinitionfromDockerfile= => transferring dockerfile: 567B=> [api] resolve [URL_WITH_CREDENTIALS] [api internal] load build definition from Dockerfile=> WARN: JSONArgsRecommended:JSONarguments recommended for CMD to prevent unintended behavior related to OS signals (line 21)=> [mcp internal] load metadata for docker.io/library/python:3.11-slim=> [api internal] load.dockerignore= => transferring context: 2B= [api 1/7] FROM docker.io/library/python:3.11-slim= [api internal] load build context= = transferring context: 60.33kB=> CACHED [api2/7J WORKDIR/app=> CACHED [api 3/7] COPY requirements.txt /app/=> CACHED [api 4/7] RUNpip install --no-cache-dir -r requirements.txt=> [api 5/7] COPY app /app/app|=> [api 6/7] COPY alembic/app/alembic[api 7/7] COPY alembic.ini /app/alembic.ini=> [api] exporting to image= => exporting layers= => writing image sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= = namingto docker.io/library/location-logger-api=> [mcp internal] load build definition from Dockerfile= => transferring dockerfile: 715B[mcp internal] loaddockerignore=> transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcр 1/6]FROM docker.io/library/python:3.11-slim=>CACHED [mcp 2/6] WORKDIR /appCACHED [mcp 3/6] COPY requirements.txt /app/CACHED[mср4/6]RUN pip install--no-cache-dir -r requirements.txt=> CACHED[mcp5/6J RUNSITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=> CACHED [mcр6/6J COPYserver.py /app/&& sed-i's/enable_dns_rebinding_protection=True/enable_dns_rebindin=> [mcp] exporting to image=>=> exportinglayers= => writingimage sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> =› naming to docker.io/library/location-logger-mcp[+] Running 3/3• Container location-logger-postgresHealthy• Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ Connection to [IP_ADDRESS] closed by remote host.Connection to [IP_ADDRESS] closed.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ |*50.0s0.050.950.0s0.0s0.0s0.050.050.0s0.0s0.150.050.050.0s0.0s0.250.250.2s0.250.2s0.0s0.050.050.0s0.0s0.0s0.050.0s0.050.050.0s0.050.0s0.0s0.0s0.0s0.050.0s0.0510.6s0.85...
|
NULL
|
-4076364071857224125
|
NULL
|
idle
|
ocr
|
NULL
|
QuickTime PlayerFileEditViewWindowHelp• Support Da QuickTime PlayerFileEditViewWindowHelp• Support Daily • in 4 h 44 m100% C78• Tue 19 May 10:16:56-zshAPP (-zsh)DOCKERO ₴1DEV (-zsh)₴82*3screenpipe"0 ₴4-zsh=>[api internal] load builddefinitionfromDockerfile= => transferring dockerfile: 567B=> [api] resolve [URL_WITH_CREDENTIALS] [api internal] load build definition from Dockerfile=> WARN: JSONArgsRecommended:JSONarguments recommended for CMD to prevent unintended behavior related to OS signals (line 21)=> [mcp internal] load metadata for docker.io/library/python:3.11-slim=> [api internal] load.dockerignore= => transferring context: 2B= [api 1/7] FROM docker.io/library/python:3.11-slim= [api internal] load build context= = transferring context: 60.33kB=> CACHED [api2/7J WORKDIR/app=> CACHED [api 3/7] COPY requirements.txt /app/=> CACHED [api 4/7] RUNpip install --no-cache-dir -r requirements.txt=> [api 5/7] COPY app /app/app|=> [api 6/7] COPY alembic/app/alembic[api 7/7] COPY alembic.ini /app/alembic.ini=> [api] exporting to image= => exporting layers= => writing image sha256:0b6f06ab29cc13dc1256d9e8240bc4bbd7ab34630040c12aae54547fb10233ec= = namingto docker.io/library/location-logger-api=> [mcp internal] load build definition from Dockerfile= => transferring dockerfile: 715B[mcp internal] loaddockerignore=> transferring context: 2B[mcp internal] load build context= transferring context: 115B[mcр 1/6]FROM docker.io/library/python:3.11-slim=>CACHED [mcp 2/6] WORKDIR /appCACHED [mcp 3/6] COPY requirements.txt /app/CACHED[mср4/6]RUN pip install--no-cache-dir -r requirements.txt=> CACHED[mcp5/6J RUNSITE=$(python -c"import sysconfig; print(sysconfig.get_path('purelib'))")=> CACHED [mcр6/6J COPYserver.py /app/&& sed-i's/enable_dns_rebinding_protection=True/enable_dns_rebindin=> [mcp] exporting to image=>=> exportinglayers= => writingimage sha256:afd9cc01d29616aa089d8ca3b164aaec06a200e88872d3ad4e2a87432aa68bc0=> =› naming to docker.io/library/location-logger-mcp[+] Running 3/3• Container location-logger-postgresHealthy• Container location-logger-apiHealthy• Container location-logger-mcpStartedAdm1n@DXP4800PLUS-B5F8:/volume2/docker/location-logger$ Connection to [IP_ADDRESS] closed by remote host.Connection to [IP_ADDRESS] closed.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe/data/data $ |*50.0s0.050.950.0s0.0s0.0s0.050.050.0s0.0s0.150.050.050.0s0.0s0.250.250.2s0.250.2s0.0s0.050.050.0s0.0s0.0s0.050.0s0.050.050.0s0.050.0s0.0s0.0s0.0s0.050.0s0.0510.6s0.85...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55980
|
NULL
|
0
|
2026-05-19T07:12:18.343256+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174738343_m2.jpg...
|
Finder
|
Work
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
2026
Yesterday at 17:06
--
Folder
#recycle
25 Apr 2026 at 20:37
--
Folder
DB
20 Jan 2026 at 10:53
--
Folder
CleanShot 2025-11-25 at 15.07.20.mp4
25 Nov 2025 at 16:04
2,63 GB
MPEG-4 movie
CleanShotX
14 Nov 2025 at 13:35
--
Folder
CleanShot 2025-10-01 at 11.28.43.mp4
1 Oct 2025 at 12:14
3,91 GB
MPEG-4 movie
CleanShot 2025-10-01 at 10.54.49.mp4
1 Oct 2025 at 11:27
2,25 GB
MPEG-4 movie
Daily 2025-07-24 2.mp4
24 Jul 2025 at 10:06
326,5 MB
MPEG-4 movie
Daily 2025-07-24.mp4
24 Jul 2025 at 10:02
1,51 GB
MPEG-4 movie
Daily 2025-07-23.mp4
23 Jul 2025 at 11:24
1,43 GB
MPEG-4 movie
IA meeting.mp4
24 Jun 2025 at 17:04
779,3 MB
MPEG-4 movie
Integration App meeting.mp4
24 Jun 2025 at 17:04
779,3 MB
MPEG-4 movie
Integration app - flows setup.mp4
18 Jun 2025 at 17:53
543,3 MB
MPEG-4 movie
IA oauth promise.mp4
18 Jun 2025 at 17:53
543,3 MB
MPEG-4 movie
Daily 2025-06-05.mp4
5 Jun 2025 at 10:46
814,3 MB
MPEG-4 movie
AI chapter 2 2025-06-04.mp4
4 Jun 2025 at 17:52
2,29 GB
MPEG-4 movie
AI chapter 1 2025-06-04.mp4
4 Jun 2025 at 17:17
1,71 GB
MPEG-4 movie
Daily 2025-06-04.mp4
4 Jun 2025 at 10:44
2,38 GB
MPEG-4 movie
Stelyan Prompts Bedrock.mp4
3 Jun 2025 at 13:47
2,46 GB
MPEG-4 movie
Stelian Prophet.mp4
3 Jun 2025 at 13:39
2,82 GB
MPEG-4 movie
IA oauth - promise.mp4
3 Jun 2025 at 12:06
1,11 GB
MPEG-4 movie
Integration App - promise on connect 2025-06-03.mp4
3 Jun 2025 at 12:06
1,11 GB
MPEG-4 movie
Galya-Iveto-Deal-Risks.mp4
30 May 2025 at 11:01
2,39 GB
MPEG-4 movie
Nudges handover Rusi 2025-04-10.mp4
10 Apr 2025 at 15:46
2,3 GB
MPEG-4 movie
Rusi-ES-handover.mp4
8 Apr 2025 at 15:12
8,51 GB
MPEG-4 movie
Stelian AskJiminny configuration 2025-03-31.mp4
31 Mar 2025 at 12:02
1,26 GB
MPEG-4 movie
AI-chapter-structured-outputs.mp4
26 Feb 2025 at 17:58
2,22 GB
MPEG-4 movie
stelian-AI-chapter-setup.mp4
12 Feb 2025 at 17:45
2,24 GB
MPEG-4 movie
IA meeting 2025-01-29 2.mp4
29 Jan 2025 at 11:27
167,4 MB
MPEG-4 movie
IA meeting 2025-01-29.mp4
29 Jan 2025 at 11:27
167,4 MB
MPEG-4 movie
Ahmet-twilio.mp4
18 Jan 2025 at 15:47
171,8 MB
MPEG-4 movie
User-Management-Tulev.mp4
18 Jan 2025 at 15:38
724 MB
MPEG-4 movie...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Favourites","depth":6,"bounds":{"left":0.5046542,"top":0.061452515,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"jiminny","depth":6,"bounds":{"left":0.51263297,"top":0.08140463,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"AirDrop","depth":6,"bounds":{"left":0.51263297,"top":0.103751,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Recents","depth":6,"bounds":{"left":0.51263297,"top":0.12609737,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Applications","depth":6,"bounds":{"left":0.51263297,"top":0.14844373,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Documents","depth":6,"bounds":{"left":0.51263297,"top":0.1707901,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Downloads","depth":6,"bounds":{"left":0.51263297,"top":0.19313647,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lukas","depth":6,"bounds":{"left":0.51263297,"top":0.21548285,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"iCloud","depth":6,"bounds":{"left":0.5046542,"top":0.2434158,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"iCloud Drive","depth":6,"bounds":{"left":0.51263297,"top":0.26336792,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sync folder","depth":6,"bounds":{"left":0.51263297,"top":0.2857143,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Locations","depth":6,"bounds":{"left":0.5046542,"top":0.31364724,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":6,"bounds":{"left":0.51263297,"top":0.33359936,"width":0.043218084,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Eject","depth":6,"bounds":{"left":0.55651593,"top":0.33519554,"width":0.0043218085,"height":0.009577015},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Network","depth":6,"bounds":{"left":0.51263297,"top":0.35594574,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tags","depth":6,"bounds":{"left":0.5046542,"top":0.38387868,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"CRM","depth":6,"bounds":{"left":0.51263297,"top":0.4038308,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Orange","depth":6,"bounds":{"left":0.51263297,"top":0.42617717,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Red","depth":6,"bounds":{"left":0.51263297,"top":0.44852355,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Yellow","depth":6,"bounds":{"left":0.51263297,"top":0.4708699,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Green","depth":6,"bounds":{"left":0.51263297,"top":0.49321628,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Blue","depth":6,"bounds":{"left":0.51263297,"top":0.51556265,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Purple","depth":6,"bounds":{"left":0.51263297,"top":0.53790903,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"All Tags…","depth":6,"bounds":{"left":0.51263297,"top":0.5602554,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Name","depth":7,"bounds":{"left":0.5827792,"top":0.06624102,"width":0.011635638,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Date Modified","depth":7,"bounds":{"left":0.8656915,"top":0.06624102,"width":0.026928192,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Size","depth":7,"bounds":{"left":0.92586434,"top":0.06624102,"width":0.008976064,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kind","depth":7,"bounds":{"left":0.9581117,"top":0.06624102,"width":0.00930851,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"2026","depth":7,"bounds":{"left":0.5827792,"top":0.08938547,"width":0.013297873,"height":0.012769354},"on_screen":true,"value":"2026","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Yesterday at 17:06","depth":7,"bounds":{"left":0.8656915,"top":0.08938547,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.9494681,"top":0.08938547,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.9581117,"top":0.08938547,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"#recycle","depth":7,"bounds":{"left":0.5827792,"top":0.105347164,"width":0.019946808,"height":0.012769354},"on_screen":true,"value":"#recycle","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"25 Apr 2026 at 20:37","depth":7,"bounds":{"left":0.8656915,"top":0.105347164,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.9494681,"top":0.105347164,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.9581117,"top":0.105347164,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"DB","depth":7,"bounds":{"left":0.5827792,"top":0.121308856,"width":0.008643617,"height":0.012769354},"on_screen":true,"value":"DB","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"20 Jan 2026 at 10:53","depth":7,"bounds":{"left":0.8656915,"top":0.121308856,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.9494681,"top":0.121308856,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.9581117,"top":0.121308856,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"CleanShot 2025-11-25 at 15.07.20.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.13727055,"width":0.08144947,"height":0.012769354},"on_screen":true,"value":"CleanShot 2025-11-25 at 15.07.20.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"25 Nov 2025 at 16:04","depth":7,"bounds":{"left":0.8656915,"top":0.13727055,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,63 GB","depth":7,"bounds":{"left":0.9368351,"top":0.13727055,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.13727055,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"CleanShotX","depth":7,"bounds":{"left":0.5827792,"top":0.15323225,"width":0.026595745,"height":0.012769354},"on_screen":true,"value":"CleanShotX","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14 Nov 2025 at 13:35","depth":7,"bounds":{"left":0.8656915,"top":0.15323225,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.9494681,"top":0.15323225,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.9581117,"top":0.15323225,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"CleanShot 2025-10-01 at 11.28.43.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.16919394,"width":0.08178192,"height":0.012769354},"on_screen":true,"value":"CleanShot 2025-10-01 at 11.28.43.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Oct 2025 at 12:14","depth":7,"bounds":{"left":0.8656915,"top":0.16919394,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3,91 GB","depth":7,"bounds":{"left":0.9368351,"top":0.16919394,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.16919394,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"CleanShot 2025-10-01 at 10.54.49.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.18515563,"width":0.08277926,"height":0.012769354},"on_screen":true,"value":"CleanShot 2025-10-01 at 10.54.49.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Oct 2025 at 11:27","depth":7,"bounds":{"left":0.8656915,"top":0.18515563,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,25 GB","depth":7,"bounds":{"left":0.9368351,"top":0.18515563,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.18515563,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2025-07-24 2.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.20111732,"width":0.05285904,"height":0.012769354},"on_screen":true,"value":"Daily 2025-07-24 2.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24 Jul 2025 at 10:06","depth":7,"bounds":{"left":0.8656915,"top":0.20111732,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"326,5 MB","depth":7,"bounds":{"left":0.93351066,"top":0.20111732,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.20111732,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2025-07-24.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.21707901,"width":0.04886968,"height":0.012769354},"on_screen":true,"value":"Daily 2025-07-24.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24 Jul 2025 at 10:02","depth":7,"bounds":{"left":0.8656915,"top":0.21707901,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,51 GB","depth":7,"bounds":{"left":0.9368351,"top":0.21707901,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.21707901,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2025-07-23.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.2330407,"width":0.04886968,"height":0.012769354},"on_screen":true,"value":"Daily 2025-07-23.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"23 Jul 2025 at 11:24","depth":7,"bounds":{"left":0.8656915,"top":0.2330407,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,43 GB","depth":7,"bounds":{"left":0.9368351,"top":0.2330407,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.2330407,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"IA meeting.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.2490024,"width":0.034574468,"height":0.012769354},"on_screen":true,"value":"IA meeting.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24 Jun 2025 at 17:04","depth":7,"bounds":{"left":0.8656915,"top":0.2490024,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"779,3 MB","depth":7,"bounds":{"left":0.93351066,"top":0.2490024,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.2490024,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Integration App meeting.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.26496407,"width":0.061835106,"height":0.012769354},"on_screen":true,"value":"Integration App meeting.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"24 Jun 2025 at 17:04","depth":7,"bounds":{"left":0.8656915,"top":0.26496407,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"779,3 MB","depth":7,"bounds":{"left":0.93351066,"top":0.26496407,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.26496407,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Integration app - flows setup.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.28092578,"width":0.07114362,"height":0.012769354},"on_screen":true,"value":"Integration app - flows setup.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"18 Jun 2025 at 17:53","depth":7,"bounds":{"left":0.8656915,"top":0.28092578,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"543,3 MB","depth":7,"bounds":{"left":0.93351066,"top":0.28092578,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.28092578,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"IA oauth promise.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.29688746,"width":0.04720745,"height":0.012769354},"on_screen":true,"value":"IA oauth promise.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"18 Jun 2025 at 17:53","depth":7,"bounds":{"left":0.8656915,"top":0.29688746,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"543,3 MB","depth":7,"bounds":{"left":0.93351066,"top":0.29688746,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.29688746,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2025-06-05.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.31284916,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"Daily 2025-06-05.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5 Jun 2025 at 10:46","depth":7,"bounds":{"left":0.8656915,"top":0.31284916,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"814,3 MB","depth":7,"bounds":{"left":0.93351066,"top":0.31284916,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.31284916,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"AI chapter 2 2025-06-04.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.32881084,"width":0.06416223,"height":0.012769354},"on_screen":true,"value":"AI chapter 2 2025-06-04.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4 Jun 2025 at 17:52","depth":7,"bounds":{"left":0.8656915,"top":0.32881084,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,29 GB","depth":7,"bounds":{"left":0.9368351,"top":0.32881084,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.32881084,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"AI chapter 1 2025-06-04.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.34477255,"width":0.06349734,"height":0.012769354},"on_screen":true,"value":"AI chapter 1 2025-06-04.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4 Jun 2025 at 17:17","depth":7,"bounds":{"left":0.8656915,"top":0.34477255,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,71 GB","depth":7,"bounds":{"left":0.9368351,"top":0.34477255,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.34477255,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Daily 2025-06-04.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.36073422,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"Daily 2025-06-04.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4 Jun 2025 at 10:44","depth":7,"bounds":{"left":0.8656915,"top":0.36073422,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,38 GB","depth":7,"bounds":{"left":0.9368351,"top":0.36073422,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.36073422,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Stelyan Prompts Bedrock.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.37669593,"width":0.06382979,"height":0.012769354},"on_screen":true,"value":"Stelyan Prompts Bedrock.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 Jun 2025 at 13:47","depth":7,"bounds":{"left":0.8656915,"top":0.37669593,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,46 GB","depth":7,"bounds":{"left":0.9368351,"top":0.37669593,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.37669593,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Stelian Prophet.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.3926576,"width":0.043882977,"height":0.012769354},"on_screen":true,"value":"Stelian Prophet.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 Jun 2025 at 13:39","depth":7,"bounds":{"left":0.8656915,"top":0.3926576,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,82 GB","depth":7,"bounds":{"left":0.9368351,"top":0.3926576,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.3926576,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"IA oauth - promise.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.4086193,"width":0.050531916,"height":0.012769354},"on_screen":true,"value":"IA oauth - promise.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 Jun 2025 at 12:06","depth":7,"bounds":{"left":0.8656915,"top":0.4086193,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,11 GB","depth":7,"bounds":{"left":0.9368351,"top":0.4086193,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.4086193,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Integration App - promise on connect 2025-06-03.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.424581,"width":0.11502659,"height":0.012769354},"on_screen":true,"value":"Integration App - promise on connect 2025-06-03.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 Jun 2025 at 12:06","depth":7,"bounds":{"left":0.8656915,"top":0.424581,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,11 GB","depth":7,"bounds":{"left":0.9368351,"top":0.424581,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.424581,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Galya-Iveto-Deal-Risks.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.4405427,"width":0.059840426,"height":0.012769354},"on_screen":true,"value":"Galya-Iveto-Deal-Risks.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 May 2025 at 11:01","depth":7,"bounds":{"left":0.8656915,"top":0.4405427,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,39 GB","depth":7,"bounds":{"left":0.9368351,"top":0.4405427,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.4405427,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Nudges handover Rusi 2025-04-10.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.45650437,"width":0.084109046,"height":0.012769354},"on_screen":true,"value":"Nudges handover Rusi 2025-04-10.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10 Apr 2025 at 15:46","depth":7,"bounds":{"left":0.8656915,"top":0.45650437,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,3 GB","depth":7,"bounds":{"left":0.93949467,"top":0.45650437,"width":0.015292553,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.45650437,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Rusi-ES-handover.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.47246608,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"Rusi-ES-handover.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8 Apr 2025 at 15:12","depth":7,"bounds":{"left":0.8656915,"top":0.47246608,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"8,51 GB","depth":7,"bounds":{"left":0.9368351,"top":0.47246608,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.47246608,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Stelian AskJiminny configuration 2025-03-31.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.4884278,"width":0.1043883,"height":0.012769354},"on_screen":true,"value":"Stelian AskJiminny configuration 2025-03-31.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"31 Mar 2025 at 12:02","depth":7,"bounds":{"left":0.8656915,"top":0.4884278,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1,26 GB","depth":7,"bounds":{"left":0.9368351,"top":0.4884278,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.4884278,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"AI-chapter-structured-outputs.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.50438946,"width":0.07480053,"height":0.012769354},"on_screen":true,"value":"AI-chapter-structured-outputs.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"26 Feb 2025 at 17:58","depth":7,"bounds":{"left":0.8656915,"top":0.50438946,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,22 GB","depth":7,"bounds":{"left":0.9368351,"top":0.50438946,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.50438946,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"stelian-AI-chapter-setup.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.5203512,"width":0.062832445,"height":0.012769354},"on_screen":true,"value":"stelian-AI-chapter-setup.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"12 Feb 2025 at 17:45","depth":7,"bounds":{"left":0.8656915,"top":0.5203512,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2,24 GB","depth":7,"bounds":{"left":0.9368351,"top":0.5203512,"width":0.017952127,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.5203512,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"IA meeting 2025-01-29 2.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.5363129,"width":0.06416223,"height":0.012769354},"on_screen":true,"value":"IA meeting 2025-01-29 2.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29 Jan 2025 at 11:27","depth":7,"bounds":{"left":0.8656915,"top":0.5363129,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"167,4 MB","depth":7,"bounds":{"left":0.93351066,"top":0.5363129,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.5363129,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"IA meeting 2025-01-29.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.5522745,"width":0.06017287,"height":0.012769354},"on_screen":true,"value":"IA meeting 2025-01-29.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29 Jan 2025 at 11:27","depth":7,"bounds":{"left":0.8656915,"top":0.5522745,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"167,4 MB","depth":7,"bounds":{"left":0.93351066,"top":0.5522745,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.5522745,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Ahmet-twilio.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.56823623,"width":0.03856383,"height":0.012769354},"on_screen":true,"value":"Ahmet-twilio.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"18 Jan 2025 at 15:47","depth":7,"bounds":{"left":0.8656915,"top":0.56823623,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"171,8 MB","depth":7,"bounds":{"left":0.93351066,"top":0.56823623,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.56823623,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"User-Management-Tulev.mp4","depth":7,"bounds":{"left":0.5827792,"top":0.58419794,"width":0.062832445,"height":0.012769354},"on_screen":true,"value":"User-Management-Tulev.mp4","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"18 Jan 2025 at 15:38","depth":7,"bounds":{"left":0.8656915,"top":0.58419794,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"724 MB","depth":7,"bounds":{"left":0.9375,"top":0.58419794,"width":0.017287234,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MPEG-4 movie","depth":7,"bounds":{"left":0.9581117,"top":0.58419794,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"}]...
|
-8528266709511006680
|
-3271035390626056807
|
click
|
accessibility
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
2026
Yesterday at 17:06
--
Folder
#recycle
25 Apr 2026 at 20:37
--
Folder
DB
20 Jan 2026 at 10:53
--
Folder
CleanShot 2025-11-25 at 15.07.20.mp4
25 Nov 2025 at 16:04
2,63 GB
MPEG-4 movie
CleanShotX
14 Nov 2025 at 13:35
--
Folder
CleanShot 2025-10-01 at 11.28.43.mp4
1 Oct 2025 at 12:14
3,91 GB
MPEG-4 movie
CleanShot 2025-10-01 at 10.54.49.mp4
1 Oct 2025 at 11:27
2,25 GB
MPEG-4 movie
Daily 2025-07-24 2.mp4
24 Jul 2025 at 10:06
326,5 MB
MPEG-4 movie
Daily 2025-07-24.mp4
24 Jul 2025 at 10:02
1,51 GB
MPEG-4 movie
Daily 2025-07-23.mp4
23 Jul 2025 at 11:24
1,43 GB
MPEG-4 movie
IA meeting.mp4
24 Jun 2025 at 17:04
779,3 MB
MPEG-4 movie
Integration App meeting.mp4
24 Jun 2025 at 17:04
779,3 MB
MPEG-4 movie
Integration app - flows setup.mp4
18 Jun 2025 at 17:53
543,3 MB
MPEG-4 movie
IA oauth promise.mp4
18 Jun 2025 at 17:53
543,3 MB
MPEG-4 movie
Daily 2025-06-05.mp4
5 Jun 2025 at 10:46
814,3 MB
MPEG-4 movie
AI chapter 2 2025-06-04.mp4
4 Jun 2025 at 17:52
2,29 GB
MPEG-4 movie
AI chapter 1 2025-06-04.mp4
4 Jun 2025 at 17:17
1,71 GB
MPEG-4 movie
Daily 2025-06-04.mp4
4 Jun 2025 at 10:44
2,38 GB
MPEG-4 movie
Stelyan Prompts Bedrock.mp4
3 Jun 2025 at 13:47
2,46 GB
MPEG-4 movie
Stelian Prophet.mp4
3 Jun 2025 at 13:39
2,82 GB
MPEG-4 movie
IA oauth - promise.mp4
3 Jun 2025 at 12:06
1,11 GB
MPEG-4 movie
Integration App - promise on connect 2025-06-03.mp4
3 Jun 2025 at 12:06
1,11 GB
MPEG-4 movie
Galya-Iveto-Deal-Risks.mp4
30 May 2025 at 11:01
2,39 GB
MPEG-4 movie
Nudges handover Rusi 2025-04-10.mp4
10 Apr 2025 at 15:46
2,3 GB
MPEG-4 movie
Rusi-ES-handover.mp4
8 Apr 2025 at 15:12
8,51 GB
MPEG-4 movie
Stelian AskJiminny configuration 2025-03-31.mp4
31 Mar 2025 at 12:02
1,26 GB
MPEG-4 movie
AI-chapter-structured-outputs.mp4
26 Feb 2025 at 17:58
2,22 GB
MPEG-4 movie
stelian-AI-chapter-setup.mp4
12 Feb 2025 at 17:45
2,24 GB
MPEG-4 movie
IA meeting 2025-01-29 2.mp4
29 Jan 2025 at 11:27
167,4 MB
MPEG-4 movie
IA meeting 2025-01-29.mp4
29 Jan 2025 at 11:27
167,4 MB
MPEG-4 movie
Ahmet-twilio.mp4
18 Jan 2025 at 15:47
171,8 MB
MPEG-4 movie
User-Management-Tulev.mp4
18 Jan 2025 at 15:38
724 MB
MPEG-4 movie...
|
55979
|
NULL
|
NULL
|
NULL
|
|
55976
|
NULL
|
0
|
2026-05-19T07:12:13.609203+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174733609_m1.jpg...
|
Finder
|
DXP4800PLUS-B5F
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
Youtube
--
--
Sharepoint
Work
--
--
Sharepoint
Test
--
--
Sharepoint
screenpipe
--
--
Sharepoint
personal_folder
--
--
Sharepoint
Music
--
--
Sharepoint
Movies
--
--
Sharepoint
Media
--
--
Sharepoint
Marti
--
--
Sharepoint
Google
--
--
Sharepoint
games
--
--
Sharepoint
Family tree documents
--
--
Sharepoint...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Favourites","depth":6,"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"jiminny","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"AirDrop","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Recents","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Applications","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Documents","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Downloads","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lukas","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"iCloud","depth":6,"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"iCloud Drive","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sync folder","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Locations","depth":6,"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Network","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tags","depth":6,"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"CRM","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Orange","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Red","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Yellow","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Green","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Blue","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Purple","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"All Tags…","depth":6,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Name","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Date Modified","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Size","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kind","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Youtube","depth":7,"on_screen":true,"value":"Youtube","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Work","depth":7,"on_screen":true,"value":"Work","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Test","depth":7,"on_screen":true,"value":"Test","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"screenpipe","depth":7,"on_screen":true,"value":"screenpipe","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"personal_folder","depth":7,"on_screen":true,"value":"personal_folder","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Music","depth":7,"on_screen":true,"value":"Music","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Movies","depth":7,"on_screen":true,"value":"Movies","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Media","depth":7,"on_screen":true,"value":"Media","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Marti","depth":7,"on_screen":true,"value":"Marti","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Google","depth":7,"on_screen":true,"value":"Google","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"games","depth":7,"on_screen":true,"value":"games","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Family tree documents","depth":7,"on_screen":true,"value":"Family tree documents","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sharepoint","depth":7,"on_screen":true,"role_description":"text"}]...
|
723401930917234316
|
-5433406441910518073
|
click
|
accessibility
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
Youtube
--
--
Sharepoint
Work
--
--
Sharepoint
Test
--
--
Sharepoint
screenpipe
--
--
Sharepoint
personal_folder
--
--
Sharepoint
Music
--
--
Sharepoint
Movies
--
--
Sharepoint
Media
--
--
Sharepoint
Marti
--
--
Sharepoint
Google
--
--
Sharepoint
games
--
--
Sharepoint
Family tree documents
--
--
Sharepoint...
|
55973
|
NULL
|
NULL
|
NULL
|
|
55911
|
NULL
|
0
|
2026-05-19T07:07:07.013043+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174427013_m1.jpg...
|
Firefox
|
Jiminny — Work
|
1
|
app.staging.jiminny.com/ai-reports
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-18091-upgrade-to-php-8-5 ■ 889125
75
75
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
Period
Report Type Report Type
Report Type
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Health - 9 - 15 Apr 2026
Weekly
Kamren Schulist
Florian Hartmann
16/04/2026
Tuesday Report - 15 Apr 2026
Daily
16/04/2026
Ask Jiminny Test Report - 15 Apr 2026
Daily
Kamren Schulist
16/04/2026
Eastern Summary - 7 - 13 Apr 2026
Weekly
14/04/2026
Tuesday Report - 13 Apr 2026
Daily
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Open Intercom Messenger...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-18091-upgrade-to-php-8-5 ■ 889125","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"75","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"75","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AI Reports","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI Reports","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Ask Jiminny reports","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny reports","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Report name","depth":17,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Period","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Report Type Report Type","depth":16,"on_screen":true,"value":"Report Type Report Type","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Report Type","depth":18,"on_screen":false,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Report Type","depth":19,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear all","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"NAME","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQUENCY","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SHARED","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACTIONS","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Health - 9 - 15 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Florian Hartmann","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tuesday Report - 15 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 15 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eastern Summary - 7 - 13 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tuesday Report - 13 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 13 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 13 Apr 2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open Intercom Messenger","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
6007417135593223934
|
5856898348684462099
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-18091-upgrade-to-php-8-5 ■ 889125
75
75
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
Period
Report Type Report Type
Report Type
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Health - 9 - 15 Apr 2026
Weekly
Kamren Schulist
Florian Hartmann
16/04/2026
Tuesday Report - 15 Apr 2026
Daily
16/04/2026
Ask Jiminny Test Report - 15 Apr 2026
Daily
Kamren Schulist
16/04/2026
Eastern Summary - 7 - 13 Apr 2026
Weekly
14/04/2026
Tuesday Report - 13 Apr 2026
Daily
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Open Intercom Messenger...
|
55905
|
NULL
|
NULL
|
NULL
|
|
55910
|
NULL
|
0
|
2026-05-19T07:06:47.685828+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174407685_m2.jpg...
|
Firefox
|
Jiminny — Work
|
1
|
app.staging.jiminny.com/ai-reports
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-18091-upgrade-to-php-8-5 ■ 889125
75
75
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
Period
Report Type Report Type
Report Type
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Health - 9 - 15 Apr 2026
Weekly
Kamren Schulist
Florian Hartmann
16/04/2026
Tuesday Report - 15 Apr 2026
Daily
16/04/2026
Ask Jiminny Test Report - 15 Apr 2026
Daily
Kamren Schulist
16/04/2026
Eastern Summary - 7 - 13 Apr 2026
Weekly
14/04/2026
Tuesday Report - 13 Apr 2026
Daily
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Open Intercom Messenger...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.041888297,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.28810853,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.31524342,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-18091-upgrade-to-php-8-5 ■ 889125","depth":9,"bounds":{"left":0.08028591,"top":0.9860335,"width":0.078457445,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"75","depth":12,"bounds":{"left":0.08228058,"top":0.91380686,"width":0.015957447,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"75","depth":14,"bounds":{"left":0.09059176,"top":0.9173983,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AI Reports","depth":13,"bounds":{"left":0.10887633,"top":0.06943336,"width":0.031416222,"height":0.019553073},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI Reports","depth":14,"bounds":{"left":0.10887633,"top":0.06943336,"width":0.031416222,"height":0.019553073},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Ask Jiminny reports","depth":13,"bounds":{"left":0.93267953,"top":0.06464485,"width":0.059341755,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny reports","depth":14,"bounds":{"left":0.94630986,"top":0.07222666,"width":0.04105718,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Report name","depth":17,"bounds":{"left":0.12167553,"top":0.10933759,"width":0.058011968,"height":0.019952115},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Period","depth":20,"bounds":{"left":0.19963431,"top":0.114924185,"width":0.012799202,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Report Type Report Type","depth":16,"bounds":{"left":0.26944813,"top":0.10933759,"width":0.06615692,"height":0.019952115},"on_screen":true,"value":"Report Type Report Type","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Report Type","depth":18,"on_screen":false,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Report Type","depth":19,"bounds":{"left":0.26944813,"top":0.11292897,"width":0.023603724,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Clear all","depth":13,"bounds":{"left":0.34192154,"top":0.112529926,"width":0.028424202,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"NAME","depth":16,"bounds":{"left":0.10854388,"top":0.1660016,"width":0.012965426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQUENCY","depth":16,"bounds":{"left":0.4895279,"top":0.1660016,"width":0.026263298,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SHARED","depth":16,"bounds":{"left":0.61668885,"top":0.1660016,"width":0.017453458,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE","depth":16,"bounds":{"left":0.7436835,"top":0.1660016,"width":0.010970744,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACTIONS","depth":16,"bounds":{"left":0.8706782,"top":0.1660016,"width":0.019115692,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.21268955,"width":0.09624335,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"bounds":{"left":0.4895279,"top":0.21268955,"width":0.016788565,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.21268955,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.25977653,"width":0.09624335,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"bounds":{"left":0.4895279,"top":0.25977653,"width":0.016788565,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.25977653,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.30686352,"width":0.09624335,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"bounds":{"left":0.4895279,"top":0.30686352,"width":0.016788565,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.30686352,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Expires On - 20 April - New - 13 - 19 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.35395053,"width":0.09624335,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monthly","depth":17,"bounds":{"left":0.4895279,"top":0.35395053,"width":0.016788565,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.35395053,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Health - 9 - 15 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.4010375,"width":0.05069814,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.4895279,"top":0.4010375,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"bounds":{"left":0.62383646,"top":0.3942538,"width":0.016456118,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Florian Hartmann","depth":18,"bounds":{"left":0.6313165,"top":0.3942538,"width":0.021276595,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.4010375,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tuesday Report - 15 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.4481245,"width":0.06299867,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"bounds":{"left":0.4895279,"top":0.4481245,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.4481245,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 15 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.49521148,"width":0.080784574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"bounds":{"left":0.4895279,"top":0.49521148,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"bounds":{"left":0.62383646,"top":0.4884278,"width":0.016456118,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.49521148,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eastern Summary - 7 - 13 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.5422985,"width":0.07363697,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.4895279,"top":0.5422985,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.5422985,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tuesday Report - 13 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.58938545,"width":0.06299867,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"bounds":{"left":0.4895279,"top":0.58938545,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.58938545,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 13 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.63647246,"width":0.080784574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"bounds":{"left":0.4895279,"top":0.63647246,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"bounds":{"left":0.62383646,"top":0.62968874,"width":0.016456118,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.63647246,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ask Jiminny Test Report - 13 Apr 2026","depth":17,"bounds":{"left":0.12184176,"top":0.6835595,"width":0.080784574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Daily","depth":17,"bounds":{"left":0.4895279,"top":0.6835595,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kamren Schulist","depth":18,"bounds":{"left":0.62383646,"top":0.67677575,"width":0.016456118,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14/04/2026","depth":17,"bounds":{"left":0.7436835,"top":0.6835595,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open Intercom Messenger","depth":7,"bounds":{"left":0.9773936,"top":0.94573027,"width":0.015957447,"height":0.03830806},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
6007417135593223934
|
5856898348684462099
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
New Tab
New Tab
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
JY-18091-upgrade-to-php-8-5 ■ 889125
75
75
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
Period
Report Type Report Type
Report Type
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Expires On - 20 April - New - 13 - 19 Apr 2026
Monthly
20/04/2026
Health - 9 - 15 Apr 2026
Weekly
Kamren Schulist
Florian Hartmann
16/04/2026
Tuesday Report - 15 Apr 2026
Daily
16/04/2026
Ask Jiminny Test Report - 15 Apr 2026
Daily
Kamren Schulist
16/04/2026
Eastern Summary - 7 - 13 Apr 2026
Weekly
14/04/2026
Tuesday Report - 13 Apr 2026
Daily
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Ask Jiminny Test Report - 13 Apr 2026
Daily
Kamren Schulist
14/04/2026
Open Intercom Messenger...
|
55901
|
NULL
|
NULL
|
NULL
|
|
55885
|
NULL
|
0
|
2026-05-19T07:01:49.120546+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174109120_m1.jpg...
|
Firefox
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira — Work...
|
1
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20676...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
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:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
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...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":19,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":20,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":18,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filters","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Filters","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Filters","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Filters","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dashboards","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dashboards","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create dashboard","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create dashboard","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Dashboards","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Dashboards","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Operations","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Operations","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
8895121136660947876
|
5933297913569267845
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
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:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
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...
|
55884
|
NULL
|
NULL
|
NULL
|
|
55883
|
NULL
|
0
|
2026-05-19T07:01:38.098969+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779174098098_m2.jpg...
|
Firefox
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira — Work...
|
1
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20676...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
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:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
More spaces
More spaces...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Project Phoenix – Figma","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Project Phoenix – Figma","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.041888297,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.28252193,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to:","depth":10,"bounds":{"left":0.090259306,"top":0.07861133,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Top Bar","depth":11,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Top Bar","depth":12,"bounds":{"left":0.090259306,"top":0.097765364,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Sidebar","depth":11,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"bounds":{"left":0.090259306,"top":0.11691939,"width":0.016954787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"bounds":{"left":0.090259306,"top":0.13607343,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":11,"bounds":{"left":0.090259306,"top":0.15522745,"width":0.037898935,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":12,"bounds":{"left":0.090259306,"top":0.15522745,"width":0.037898935,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"bounds":{"left":0.08361037,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"bounds":{"left":0.0887633,"top":0.06344773,"width":0.039727394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"bounds":{"left":0.095578454,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":13,"bounds":{"left":0.10073138,"top":0.06344773,"width":0.044215426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.027759308,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"bounds":{"left":0.08361037,"top":0.15083799,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":16,"bounds":{"left":0.09424867,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"bounds":{"left":0.08361037,"top":0.1763767,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":16,"bounds":{"left":0.09424867,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"bounds":{"left":0.15309176,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"bounds":{"left":0.08361037,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"bounds":{"left":0.09424867,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"bounds":{"left":0.13646941,"top":0.20510775,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for spaces","depth":14,"bounds":{"left":0.14577793,"top":0.20510775,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for spaces","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recent","depth":17,"bounds":{"left":0.08959442,"top":0.23423783,"width":0.013464096,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Service-Desk","depth":18,"bounds":{"left":0.08759973,"top":0.2529928,"width":0.0674867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Service-Desk","depth":21,"bounds":{"left":0.09823803,"top":0.25897846,"width":0.03025266,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Service-Desk","depth":19,"bounds":{"left":0.15442154,"top":0.25618514,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Service-Desk","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny (New)","depth":18,"bounds":{"left":0.08759973,"top":0.27853152,"width":0.0674867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny (New)","depth":21,"bounds":{"left":0.09823803,"top":0.28451717,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Jiminny (New)","depth":19,"bounds":{"left":0.08892952,"top":0.28172386,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXMenuButton","text":"Create board","depth":19,"bounds":{"left":0.13646941,"top":0.28172386,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Create board","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Jiminny (New)","depth":19,"bounds":{"left":0.14577793,"top":0.28172386,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Jiminny (New)","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Platform Team","depth":20,"bounds":{"left":0.09158909,"top":0.30407023,"width":0.06349734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team","depth":23,"bounds":{"left":0.1022274,"top":0.31005585,"width":0.032247342,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.30726257,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Capture Team","depth":20,"bounds":{"left":0.09158909,"top":0.32960895,"width":0.06349734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Capture Team","depth":23,"bounds":{"left":0.1022274,"top":0.33559456,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.33280128,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Enterprise Stability Issues 🤕","depth":20,"bounds":{"left":0.09158909,"top":0.35514766,"width":0.06349734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enterprise Stability Issues 🤕","depth":23,"bounds":{"left":0.1022274,"top":0.36113328,"width":0.050531916,"height":0.030726258},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.35834,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Processing Team","depth":20,"bounds":{"left":0.09158909,"top":0.38068634,"width":0.06349734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Processing Team","depth":23,"bounds":{"left":0.1022274,"top":0.386672,"width":0.038231384,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.38387868,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SE Kanban","depth":20,"bounds":{"left":0.09158909,"top":0.40622506,"width":0.06349734,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SE Kanban","depth":23,"bounds":{"left":0.1022274,"top":0.4122107,"width":0.024102394,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Board actions","depth":21,"bounds":{"left":0.15309176,"top":0.4094174,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Board actions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More spaces","depth":18,"bounds":{"left":0.08759973,"top":0.43176377,"width":0.0674867,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More spaces","depth":21,"bounds":{"left":0.09823803,"top":0.43774942,"width":0.028756648,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-346840896182040258
|
5969322312540639397
|
idle
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
Project Phoenix – Figma
Project Phoenix – Figma
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
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:
Top Bar
Top Bar
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
Notifications
Notifications
Help
Help
Settings
Settings
[EMAIL]
[EMAIL]
For you
For you
Recent
Recent
Starred
Starred
Apps
Apps
More actions for Apps
More actions for Apps
Spaces
Spaces
Create space
Create space
More actions for spaces
More actions for spaces
Recent
Service-Desk
Service-Desk
More actions for Service-Desk
More actions for Service-Desk
Jiminny (New)
Jiminny (New)
Jiminny (New)
Create board
Create board
More actions for Jiminny (New)
More actions for Jiminny (New)
Platform Team
Platform Team
Board actions
Board actions
Capture Team
Capture Team
Board actions
Board actions
Enterprise Stability Issues 🤕
Enterprise Stability Issues 🤕
Board actions
Board actions
Processing Team
Processing Team
Board actions
Board actions
SE Kanban
SE Kanban
Board actions
Board actions
More spaces
More spaces...
|
55879
|
NULL
|
NULL
|
NULL
|
|
55829
|
NULL
|
0
|
2026-05-19T06:57:03.648529+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173823648_m1.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
11:43
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"11:43","depth":1,"bounds":{"left":0.7451389,"top":0.94722223,"width":0.028472222,"height":0.015555556},"on_screen":true,"role_description":"text"}]...
|
7821262348185964639
|
7821262348185964639
|
visual_change
|
hybrid
|
NULL
|
11:43
FirefoxFileEditViewHistoryBookmarksProfilesT 11:43
FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/agt-teir-cwt?authuser=lukas.kovalik%40jiminny.comDaily - Platform • 8 m left100% C8• Tue 19 May 9:57:03Nikolay Yankov (Presenting)© Cursor -a DatadogCostiC xaco.devxG Alow о3 PoelineC DevTue 19 May 9:67L Al Bookmarxsl•S88Platform Team %.Q Search boardKADTTOK OWENotify the user id aAJ REPORTSBackiоgД JY-200763 .**=©Notify the user if a SS isdeleted but is used in AJReportAJREPORTSBacklogД JY-20615|2.5 •000 =Upgrade BE Ibraries - MayMAINTENANCISваскіюяіE JY-19958•****=©AnsrowencvlwsuggestionsAUTO-DETEGTED AGTIVITY TYPP JY-204702 ***= 117 Service-https://fiminny.atlassian.net/jra/software/c/projects/JJY/boards/37C Projects|8800018Eplc ~TypeMCP > Enabie users to getJIMINNY MCP CONNECTORIn Dev( JY-20833•****=0MCP > Enable users to getsustor ocais and tneildetallsJMINNY MOP CONNECTORIn DevД Jy-20835 20 0 ***=LATUS Group - Exec|Summary InaccuracySUPPORT TICKETSIn DevJY-ZO0W*AttenticQuick TitersvUpgrade to PHP 8.5PHP E.S UPGRADEReady for QA|@л-м0n 15 1l ***=OMCP > Enable the AI tomion octais about the uschReady for QA|Д л-2084615 л =0Allow owner's role to beselected when setting up atrialEMPROVEMENT OF OUR EFFECRINCY0J4-2061315 1 =0Group: QueriesAJ Panorama for Call|Scoring nouAUTOMATED AI SCORINGDeployedP 3y-20361 05[HubSpot) Optimise CRMrematching on deletenoospos accountsrconsactsCCATFORM STARTUTYDeployedXE-JY-20725[Deadline 25 May) Migratedepricated Gemini 3.1 FlashSetup test coverage forBл-ws 0 •= 1Upgrade Python andNikolay YankovStefka Stoyanova2 othersNikolay Ivanov9:57 AM | Daily - PlatformLukas Kovalik11:43...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55827
|
NULL
|
0
|
2026-05-19T06:56:54.474838+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173814474_m2.jpg...
|
CleanShot X
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
11:34
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"11:34","depth":1,"on_screen":true,"role_description":"text"}]...
|
-6384641152190199095
|
-6384641152190199095
|
idle
|
hybrid
|
NULL
|
11:34
rireroxCaltMIstorybookmarksProtllesWindowDal 11:34
rireroxCaltMIstorybookmarksProtllesWindowDally - Platorm• ym len100% 12• lue 1y May 9:00:04.• 0-7 Imoort bookmarks.• Sprint Board SRD Queue# Jiminnv DEV(O Circle CI & PROD US & Staging al) SentryPull requests • jimin..Workers | Datadog M Jiminny Mail Dashboards | Datad..Platform Sorint 4 02 - Platform TelService-Desk - Queues - Platforn22°CNew York Cily• Jy-20725 add HS rate limit handlitJY-20808 low priority indexing qu0 Pipelines - jiminny/appNew Tab- New TabFirefoxsearch with Google or enter addressPlatform Sarint...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55781
|
NULL
|
0
|
2026-05-19T06:51:50.037077+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173510037_m1.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
1
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-2315879924887151426
|
5784383345260286085
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)...
|
55780
|
NULL
|
NULL
|
NULL
|
|
55778
|
NULL
|
0
|
2026-05-19T06:51:34.110030+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173494110_m2.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
1
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
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 sidecars
Chunk sidecars
PREVIEW
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
58533
58533
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
23m 44s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-18091-upgrade-to-php-8-5
JY-18091-upgrade-to-php-8-5
Open commit on version control site
0b8343d
Merge branch 'master' into JY-18091-upgrade-to-php-8-5
Push
Commit pushed
Copy timestamp to clipboard
1m 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
889119
1m 5s
1m 5s
RUNNING job build-frontend
build-frontend
889123
10s
10s
test-frontend...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.18994413,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.21707901,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"bounds":{"left":0.08726729,"top":0.061452515,"width":0.044215426,"height":0.031923383},"on_screen":true,"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.9375,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"bounds":{"left":0.95212764,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"bounds":{"left":0.96675533,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"bounds":{"left":0.98138297,"top":0.061452515,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"bounds":{"left":0.08693484,"top":0.10295291,"width":0.01462766,"height":0.035115723},"on_screen":true,"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.08494016,"top":0.15083799,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.087765954,"top":0.1839585,"width":0.012965426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"bounds":{"left":0.08494016,"top":0.21308859,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.083942816,"top":0.2462091,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"bounds":{"left":0.08494016,"top":0.2753392,"width":0.01861702,"height":0.04668795},"on_screen":true,"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.0852726,"top":0.3084597,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"bounds":{"left":0.08494016,"top":0.33798882,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.08543883,"top":0.37071028,"width":0.01761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"bounds":{"left":0.08494016,"top":0.40023944,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.085605055,"top":0.4329609,"width":0.017287234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"bounds":{"left":0.08494016,"top":0.46249002,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.0852726,"top":0.49561054,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"bounds":{"left":0.08494016,"top":0.52474064,"width":0.01861702,"height":0.046288908},"on_screen":true,"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.090259306,"top":0.55786115,"width":0.007978723,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"bounds":{"left":0.08494016,"top":0.58699125,"width":0.01861702,"height":0.04668795},"on_screen":true,"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.08959442,"top":0.6201117,"width":0.00930851,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk sidecars","depth":11,"bounds":{"left":0.07962101,"top":0.8591381,"width":0.02925532,"height":0.059457302},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk sidecars","depth":13,"bounds":{"left":0.08494016,"top":0.8922586,"width":0.01861702,"height":0.026735835},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PREVIEW","depth":12,"bounds":{"left":0.08743351,"top":0.8567438,"width":0.013630319,"height":0.009177973},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"bounds":{"left":0.07962101,"top":0.9345571,"width":0.02925532,"height":0.046288908},"on_screen":true,"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.08726729,"top":0.96727854,"width":0.013962766,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":12,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":12,"on_screen":false,"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":12,"on_screen":false,"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":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":12,"on_screen":false,"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":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":12,"on_screen":false,"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":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":12,"on_screen":false,"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":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":12,"on_screen":false,"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":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":13,"bounds":{"left":0.12250665,"top":0.0,"width":0.015292553,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":13,"bounds":{"left":0.28740028,"top":0.0,"width":0.012632979,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":13,"bounds":{"left":0.34424868,"top":0.0,"width":0.018450798,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":13,"bounds":{"left":0.5731383,"top":0.0,"width":0.03274601,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":13,"bounds":{"left":0.70611703,"top":0.0,"width":0.025764627,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":13,"bounds":{"left":0.8640292,"top":0.0,"width":0.009640957,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":13,"bounds":{"left":0.90226066,"top":0.0,"width":0.01662234,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":13,"bounds":{"left":0.92952126,"top":0.0,"width":0.014793883,"height":0.011971269},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":12,"bounds":{"left":0.12283909,"top":0.0,"width":0.00831117,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58533","depth":11,"bounds":{"left":0.12283909,"top":0.0,"width":0.014461436,"height":0.015961692},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58533","depth":12,"bounds":{"left":0.12283909,"top":0.0,"width":0.014461436,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":12,"bounds":{"left":0.27759308,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":11,"bounds":{"left":0.28956118,"top":0.0,"width":0.03274601,"height":0.023144454},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":12,"bounds":{"left":0.30019948,"top":0.0,"width":0.018118352,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"23m 44s","depth":12,"bounds":{"left":0.28956118,"top":0.0,"width":0.019448139,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":12,"bounds":{"left":0.3090093,"top":0.0,"width":0.016289894,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":11,"bounds":{"left":0.3259641,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":11,"bounds":{"left":0.3444149,"top":0.0,"width":0.045545213,"height":0.01556265},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":12,"bounds":{"left":0.3444149,"top":0.0,"width":0.045545213,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-18091-upgrade-to-php-8-5","depth":12,"bounds":{"left":0.5728058,"top":0.0,"width":0.069148935,"height":0.01556265},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-18091-upgrade-to-php-8-5","depth":13,"bounds":{"left":0.5728058,"top":0.0,"width":0.069148935,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":13,"bounds":{"left":0.5728058,"top":0.0,"width":0.12765957,"height":0.033519555},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0b8343d","depth":15,"bounds":{"left":0.5728058,"top":0.0,"width":0.020777926,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merge branch 'master' into JY-18091-upgrade-to-php-8-5","depth":15,"bounds":{"left":0.5728058,"top":0.0,"width":0.12649602,"height":0.030726258},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":12,"bounds":{"left":0.7190825,"top":0.0,"width":0.011303191,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":13,"bounds":{"left":0.73171544,"top":0.0,"width":0.034574468,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":12,"bounds":{"left":0.8515625,"top":0.0,"width":0.027094414,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m ago","depth":14,"bounds":{"left":0.8572141,"top":0.0,"width":0.015791224,"height":0.01396648},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":12,"bounds":{"left":0.8969415,"top":0.0,"width":0.026928192,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":11,"bounds":{"left":0.92918885,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":11,"bounds":{"left":0.93982714,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":11,"bounds":{"left":0.95046544,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":11,"bounds":{"left":0.96110374,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":11,"bounds":{"left":0.97174203,"top":0.0,"width":0.010638298,"height":0.025538707},"on_screen":false,"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":13,"bounds":{"left":0.26080453,"top":0.022745412,"width":0.010804521,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":13,"bounds":{"left":0.28756648,"top":0.020351157,"width":0.41805187,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":14,"bounds":{"left":0.30285904,"top":0.022745412,"width":0.03374335,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"889119","depth":15,"bounds":{"left":0.33926198,"top":0.022745412,"width":0.015791224,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 5s","depth":13,"bounds":{"left":0.90525264,"top":0.020351157,"width":0.013297873,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 5s","depth":14,"bounds":{"left":0.90525264,"top":0.022745412,"width":0.013297873,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"RUNNING job build-frontend","depth":13,"bounds":{"left":0.28756648,"top":0.045889866,"width":0.41805187,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":14,"bounds":{"left":0.30285904,"top":0.048284117,"width":0.032247342,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"889123","depth":15,"bounds":{"left":0.33776596,"top":0.048284117,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"10s","depth":13,"bounds":{"left":0.91073805,"top":0.045889866,"width":0.0078125,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10s","depth":14,"bounds":{"left":0.91073805,"top":0.048284117,"width":0.0078125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test-frontend","depth":14,"bounds":{"left":0.30285904,"top":0.073822826,"width":0.029421542,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
7603357447515985487
|
6054634506536415361
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Service-Desk - Queues - Platform team - Service space - Jira
Service-Desk - Queues - Platform team - Service space - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
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 sidecars
Chunk sidecars
PREVIEW
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
58533
58533
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
23m 44s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-18091-upgrade-to-php-8-5
JY-18091-upgrade-to-php-8-5
Open commit on version control site
0b8343d
Merge branch 'master' into JY-18091-upgrade-to-php-8-5
Push
Commit pushed
Copy timestamp to clipboard
1m 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
889119
1m 5s
1m 5s
RUNNING job build-frontend
build-frontend
889123
10s
10s
test-frontend...
|
55777
|
NULL
|
NULL
|
NULL
|
|
55737
|
NULL
|
0
|
2026-05-19T06:46:48.303935+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173208303_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.0051529254,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"bounds":{"left":0.20578457,"top":0.00518755,"width":0.0066489363,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"bounds":{"left":0.20578457,"top":0.06264964,"width":0.03374335,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"bounds":{"left":0.20578457,"top":0.12011173,"width":0.13131648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"bounds":{"left":0.20578457,"top":0.17757383,"width":0.12732713,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"bounds":{"left":0.20578457,"top":0.25418994,"width":0.13314494,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"bounds":{"left":0.20578457,"top":0.33080608,"width":0.12865691,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"bounds":{"left":0.20578457,"top":0.40742218,"width":0.004155585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.42657623,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"bounds":{"left":0.20578457,"top":0.44573024,"width":0.065990694,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.46488428,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"bounds":{"left":0.20578457,"top":0.4840383,"width":0.08028591,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5415004,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.5606544,"width":0.12117686,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5798085,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.5989625,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.6181165,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"bounds":{"left":0.20578457,"top":0.63727057,"width":0.053025264,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.6564246,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.6755786,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7138867,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.7330407,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.75219476,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.7713488,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"bounds":{"left":0.20578457,"top":0.8288109,"width":0.09375,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.88627297,"width":0.10388963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":0.924581,"width":0.1356383,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.1356383,"height":-0.0011970997},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.058659196},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.13115026,"height":-0.09696722},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
92836160000943306
|
-1126437240719860594
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55735
|
NULL
|
0
|
2026-05-19T06:46:43.984290+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779173203984_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-8673834039729196461
|
-1127563132036899698
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:...
|
55734
|
NULL
|
NULL
|
NULL
|
|
55695
|
NULL
|
0
|
2026-05-19T06:41:32.663057+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172892663_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-e5d github.com/jiminny/app/pull/12082/changes#diff-e5dcbcff071d212d7289a3afae523499caf0603272c50b6da48a278910b9ca09...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function getAllIds(): array","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function markStale(): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->isStaleChunkSelected = true;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
4141898300521863576
|
-1126437240719860594
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}
public function getAllIds(): array
public function markStale(): void
{
{
return array_merge($this->priorityEntityIdList, $this->normalEntityIdList);
$this->isStaleChunkSelected = true;
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55694
|
NULL
|
0
|
2026-05-19T06:41:19.120729+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172879120_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-49a github.com/jiminny/app/pull/12082/changes#diff-49a79d99c97caf7fc27ecb1dbacab5a29d871822caa0db0c71e94957c28c87af...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show the uploaded image in a lightbox","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Make a PR of changes Find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Make a PR of changes Find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"However,","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"the image resolution is far too low for me to read.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How You Can Share the Code","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How You Can Share the Code","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To help me review your code effectively, please try one of the following:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Paste the text directly:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upload the files:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the changes are extensive, you can upload the raw text or code files.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Take high-resolution screenshots:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.17121011,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.18583776,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners; namespace Jiminny\\Component\\ES\\Listeners; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity; use Psr\\Log\\LoggerInterface; use Psr\\Log\\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidDataException; use Jiminny\\Exceptions\\InvalidDataException; use Sentry\\Laravel\\Facade as Sentry; use Sentry\\Laravel\\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\\Component\\ES\\Processor\\DTOs; namespace Jiminny\\Component\\ES\\Processor\\DTOs; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\\Support\\Facades\\Log; use Illuminate\\Support\\Facades\\Log; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ExtractIdsTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait; use Jiminny\\Component\\ES\\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\\Component\\ES; use Jiminny\\Exceptions\\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority \"%s\" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\\Support\\Str; use Illuminate\\Support\\Str; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Component\\ES\\UpdateProcessManager; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\Traits\\ValidateUpdateTargetTrait; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\Processor\\UpdateTarget; use Jiminny\\Component\\ES\\QueuePriorityEnum; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Component\\ES\\Repositories\\EsResetRepositoryInterface; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Exceptions\\InvalidArgumentException; use Jiminny\\Traits\\GracefullyStoppable; use Jiminny\\Traits\\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(","depth":21,"bounds":{"left":0.20578457,"top":0.0,"width":0.13696809,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.0,"width":0.019946808,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateMultipleTargetsListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.0,"width":0.084773935,"height":0.035514764},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.0007980846,"width":0.10388963,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.039106146,"width":0.11303192,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Listeners;","depth":23,"bounds":{"left":0.20578457,"top":0.096568234,"width":0.1100399,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.15403032,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.17318435,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":0.23064645,"width":0.115359046,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.24980047,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateMultipleEntities;","depth":23,"bounds":{"left":0.20578457,"top":0.26895452,"width":0.13597074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.28810853,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":0.30726257,"width":0.07047872,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.36472467,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(","depth":23,"bounds":{"left":0.20578457,"top":0.38387868,"width":0.13530585,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.40303272,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"bounds":{"left":0.20578457,"top":0.42218676,"width":0.0809508,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.44134077,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntities(),","depth":23,"bounds":{"left":0.20578457,"top":0.46049482,"width":0.052526597,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"bounds":{"left":0.20578457,"top":0.47964883,"width":0.046708778,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"bounds":{"left":0.20578457,"top":0.49880287,"width":0.11702128,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.5371109,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"bounds":{"left":0.20578457,"top":0.55626494,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.575419,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.594573,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.61372703,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"bounds":{"left":0.20578457,"top":0.6328811,"width":0.0019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Listeners/UpdateSingleTargetListener.php","depth":23,"bounds":{"left":0.20578457,"top":0.6520351,"width":0.07762633,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+9-1Lines changed: 9 additions & 1 deletion","depth":23,"bounds":{"left":0.20578457,"top":0.7094972,"width":0.104222074,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.74780524,"width":0.13480718,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Actions\\TrackElasticSearchOperations;","depth":23,"bounds":{"left":0.20578457,"top":0.8244214,"width":0.13480718,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.8818835,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\AsyncUpdateElasticSearch;","depth":23,"bounds":{"left":0.20578457,"top":0.9010375,"width":0.13380983,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.9201915,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;","depth":23,"bounds":{"left":0.20578457,"top":0.9584996,"width":0.1306516,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.115359046,"height":-0.03511572},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12732713,"height":-0.05426979},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Contracts\\ES\\Events\\UpdateSingleEntity;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.12732713,"height":-0.07342374},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"bounds":{"left":0.20578457,"top":1.0,"width":0.07047872,"height":-0.092577815},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Psr\\Log\\LoggerInterface;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"'entityId' => $event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"]);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* @important:","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Synchronous event should eventually be deprecated.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Instant write operations are blocking and should be used sparingly.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* It is much better in terms of performance to write 100 or 1000 documents at once,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* and have one blocking reindex operation, instead of writing 10 documents synchronously.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if ($event->isSyncEvent()) {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->handleSyncEvent($event);","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getUpdateTargetValue(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->getEntityId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority()","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/Actions/UpsertDocumentsAction.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+2-1Lines changed: 2 additions & 1 deletion","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\ResponseEvaluator;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\Processor\\Traits\\UpdateTargetTrait;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Exceptions\\InvalidDataException;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Sentry\\Laravel\\Facade as Sentry;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AsyncUpdateElasticSearch::markEntityForUpdate(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityType: $this->updateTarget,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entityId: (int) $document->getId(),","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"withPriority: true","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"priority: QueuePriorityEnum::HIGH,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":");","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app/Component/ES/Processor/DTOs/SelectionList.php","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+54-17Lines changed: 54 additions & 17 deletions","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line numberOriginal file lineDiff line numberDiff line change","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace Jiminny\\Component\\ES\\Processor\\DTOs;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"use Jiminny\\Component\\ES\\QueuePriorityEnum;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/**","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* A very basic and simple collection of entity IDs.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*/","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class SelectionList","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function __construct(","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private const int DEFAULT_CHUNK = 200;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $priorityEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly array $normalEntityIdList = [],","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private int $chunkSize = self::DEFAULT_CHUNK;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly bool $isStaleChunkSelected = false,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private bool $isStaleChunkSelected = false;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private readonly int $chunkSize = 200,","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"private array $selectedEntityIds = [];","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") {","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"// Do nothing","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public function setChunkSize(int $chunkSize): void","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$this->chunkSize = $chunkSize;","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"}","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
504577837169412428
|
-1127563140626703218
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Show the uploaded image in a lightbox
Copy prompt
You said Make a PR of changes Find potential issues and bottlenecks
You said
Make a PR of changes Find potential issues and bottlenecks
Listen
Show thinking
Gemini said
Gemini said
I can see you've uploaded a screenshot of a code diff, likely from a version control system given the red and green highlights. I would love to help you review the changes, spot bottlenecks, and help you draft a Pull Request.
However,
the image resolution is far too low for me to read.
It appears to be a completely zoomed-out view where the code has been reduced to tiny, illegible pixels. Because of this, I cannot extract any text or logic to analyze.
How You Can Share the Code
How You Can Share the Code
To help me review your code effectively, please try one of the following:
Paste the text directly:
Copy the specific code blocks (both the old and new versions if possible) and paste them directly into our chat.
Upload the files:
If the changes are extensive, you can upload the raw text or code files.
Take high-resolution screenshots:
If you must use images, take closer, readable screenshots of the specific functions or methods you want me to review.
Once you provide the readable code, I can dive right in to identify potential bugs, assess performance bottlenecks, and help you summarize the changes for your PR!
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said app/Component/ES/Listeners/UpdateMultipleTargetsListener.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners; namespace Jiminny\Component\ES\Listeners; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Jiminny\Contracts\ES\Events\UpdateMultipleEntities; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntities(), $event->getEntities(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } } } app/Component/ES/Listeners/UpdateSingleTargetListener.php +9-1Lines changed: 9 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\Actions\TrackElasticSearchOperations; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Jiminny\Contracts\ES\Events\UpdateSingleEntity; use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface; 'entityId' => $event->getEntityId(), 'entityId' => $event->getEntityId(), ]); ]); /** * @important: * Synchronous event should eventually be deprecated. * Instant write operations are blocking and should be used sparingly. * It is much better in terms of performance to write 100 or 1000 documents at once, * and have one blocking reindex operation, instead of writing 10 documents synchronously. */ if ($event->isSyncEvent()) { if ($event->isSyncEvent()) { $this->handleSyncEvent($event); $this->handleSyncEvent($event); AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( $event->getUpdateTargetValue(), $event->getUpdateTargetValue(), $event->getEntityId(), $event->getEntityId(), $event->isPriority() $event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL, ); ); } } app/Component/ES/Processor/Actions/UpsertDocumentsAction.php +2-1Lines changed: 2 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\DTOs\SimpleCollection; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\ResponseEvaluator; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidDataException; use Jiminny\Exceptions\InvalidDataException; use Sentry\Laravel\Facade as Sentry; use Sentry\Laravel\Facade as Sentry; AsyncUpdateElasticSearch::markEntityForUpdate( AsyncUpdateElasticSearch::markEntityForUpdate( entityType: $this->updateTarget, entityType: $this->updateTarget, entityId: (int) $document->getId(), entityId: (int) $document->getId(), withPriority: true priority: QueuePriorityEnum::HIGH, ); ); } } app/Component/ES/Processor/DTOs/SelectionList.php +54-17Lines changed: 54 additions & 17 deletions Original file line numberOriginal file lineDiff line numberDiff line change namespace Jiminny\Component\ES\Processor\DTOs; namespace Jiminny\Component\ES\Processor\DTOs; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * A very basic and simple collection of entity IDs. * A very basic and simple collection of entity IDs. */ */ class SelectionList class SelectionList { { public function __construct( private const int DEFAULT_CHUNK = 200; private readonly array $priorityEntityIdList = [], private readonly array $normalEntityIdList = [], private int $chunkSize = self::DEFAULT_CHUNK; private readonly bool $isStaleChunkSelected = false, private bool $isStaleChunkSelected = false; private readonly int $chunkSize = 200, private array $selectedEntityIds = []; ) { // Do nothing public function setChunkSize(int $chunkSize): void { $this->chunkSize = $chunkSize; } } public function getAllIds(): array public function markStale(): void { { return array_merge($this->priorityEntityIdList, $this->normalEntityIdList); $this->isStaleChunkSelected = true; } } public function count(): int public function addEntityList(string|QueuePriorityEnum $priority, array $entityIds): void { { return count($this->priorityEntityIdList) + count($this->normalEntityIdList); $priorityKey = $this->normalisePriority($priority); if (! array_key_exists($priorityKey, $this->selectedEntityIds)) { $this->selectedEntityIds[$priorityKey] = []; } $this->selectedEntityIds[$priorityKey] = array_merge($this->selectedEntityIds[$priorityKey], $entityIds); } } public function isEmpty(): bool /** * @return string[] */ public function getEntityListGroups(): array { { return empty($this->priorityEntityIdList) && empty($this->normalEntityIdList); return array_keys($this->selectedEntityIds); } } public function getHighPriorityEntityIds(): array public function getEntityListItemsByGroup(string|QueuePriorityEnum $priority): array { { return $this->priorityEntityIdList; $priorityKey = $this->normalisePriority($priority); return $this->selectedEntityIds[$priorityKey] ?? []; } } public function getNormalPriorityEntityId(): array public function getAllIds(): array { { return $this->normalEntityIdList; $allIds = []; foreach ($this->selectedEntityIds as $entityIds) { $allIds = array_merge($allIds, $entityIds); } return $allIds; } public function count(): int { return array_sum( array_map('count', $this->selectedEntityIds) ); } public function isEmpty(): bool { return $this->count() === 0; } } public function isStaleChunkSelected(): bool public function isStaleChunkSelected(): bool { { return $this->count() >= $this->chunkSize; return $this->count() >= $this->chunkSize; } } private function normalisePriority(string|QueuePriorityEnum $priority): string { return $priority instanceof QueuePriorityEnum ? $priority->value : $priority; } } } app/Component/ES/Processor/Traits/SelectEntityListTrait.php +27-4Lines changed: 27 additions & 4 deletions Original file line numberOriginal file lineDiff line numberDiff line change use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; /** /** * Build the correct source list name for the type of entity and priority * Build the correct source list name for the type of entity and priority */ */ trait SelectEntityListTrait trait SelectEntityListTrait { { /** * Highest priority queue for data requiring near-instant availability. * Very few entities should be added here, only when absolutely necessary. */ private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; /** * Normal priority queue for normal application operations. * Almost all update events should pass through this queue */ private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_NORMAL_PRIORITIES_LIST = '%s-for-update'; private const string ENTITIES_HIGH_PRIORITIES_LIST = '%s-for-update-priority'; protected static function selectTargetList(string $entityType, bool $withPriority = false): string /** { * Nonblocking low priority queue. This queue will be consumed only when there is nothing * with higher priority. * * This queue will be used for operations such as es:reset-async */ private const string ENTITIES_LOW_PRIORITIES_LIST = '%s-for-update-low'; protected static function selectTargetList( string $entityType, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { if (! in_array($entityType, UpdateTarget::allowedTargets())) { if (! in_array($entityType, UpdateTarget::allowedTargets())) { throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); throw new InvalidArgumentException('AsyncUpdateElasticSearch, invalid entity type'); } } if ($withPriority) { if ($priority->isHigh()) { Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); Log::debug('[AsyncUpdateElasticSearch] - Priority check passed and priority is on'); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_HIGH_PRIORITIES_LIST, $entityType); } } if ($priority->isLow()) { return sprintf(self::ENTITIES_LOW_PRIORITIES_LIST, $entityType); } return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); return sprintf(self::ENTITIES_NORMAL_PRIORITIES_LIST, $entityType); } } } } app/Component/ES/Processor/TargetEntitiesSelector.php +26-21Lines changed: 26 additions & 21 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\DTOs\SelectionList; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\ExtractIdsTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait; use Jiminny\Component\ES\QueuePriorityEnum; /** /** * This class supplies a list of entities pending an update. * This class supplies a list of entities pending an update. public function select(): SelectionList public function select(): SelectionList { { $staleWorkEntityIds = $this->getStaleChunk(); $selectionList = new SelectionList(); $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $staleWorkEntityIds = $this->getStaleChunk(); if (count($staleWorkEntityIds) > 0) { if (count($staleWorkEntityIds) > 0) { return new SelectionList( /** priorityEntityIdList: $staleWorkEntityIds, * Stale chunks are treated as high priority isStaleChunkSelected: true, */ chunkSize: ChunkSize::getStaleChunkSize($this->updateTarget), $selectionList->markStale(); ); $selectionList->addEntityList(QueuePriorityEnum::HIGH, $staleWorkEntityIds); $selectionList->setChunkSize(ChunkSize::getStaleChunkSize($this->updateTarget)); return $selectionList; } } $mainChunkSize = ChunkSize::getMainChunkSize($this->updateTarget); $selectionList->setChunkSize($mainChunkSize); $priorityEntityIdsList = $this->extractIdsFromSet( $priorityEntityIdsList = $this->extractIds(QueuePriorityEnum::HIGH, $mainChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, true), $selectionList->addEntityList(QueuePriorityEnum::HIGH, $priorityEntityIdsList); $mainChunkSize, ); $normalEntityIdsList = []; $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); $normalEntityChunkSize = $mainChunkSize - count($priorityEntityIdsList); if ($normalEntityChunkSize > 0) { if ($normalEntityChunkSize > 0) { $normalEntityIdsList = $this->extractIdsFromSet( $normalEntityIdsList = $this->extractIds(QueuePriorityEnum::NORMAL, $normalEntityChunkSize); AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, false), $selectionList->addEntityList(QueuePriorityEnum::NORMAL, $normalEntityIdsList); $normalEntityChunkSize ); } } return new SelectionList( return $selectionList; priorityEntityIdList: $priorityEntityIdsList, normalEntityIdList: $normalEntityIdsList, chunkSize: $mainChunkSize ); } } private function getStaleChunk(): array private function getStaleChunk(): array return []; return []; } } private function extractIds(QueuePriorityEnum $priority, int $chunkSize): array { return $this->extractIdsFromSet( AsyncUpdateElasticSearch::getEntitiesSourceList($this->updateTarget, $priority), $chunkSize ); } } } app/Component/ES/AsyncUpdateElasticSearch.php +17-10Lines changed: 17 additions & 10 deletions Original file line numberOriginal file lineDiff line numberDiff line change * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * Various methods and actions call this method to rebuild auto-score, plays, shares, topic triggers * and other activity related data * and other activity related data */ */ public static function markEntityForUpdate(string $entityType, int $entityId, bool $withPriority = false): void public static function markEntityForUpdate( { string $entityType, $targetList = self::selectTargetList($entityType, $withPriority); int $entityId, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { $targetList = self::selectTargetList($entityType, $priority); Redis::sadd($targetList, $entityId); Redis::sadd($targetList, $entityId); Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ Log::info('[ AsyncUpdateElasticSearch ] Entity added to Redis list', [ 'entityType' => $entityType, 'entityType' => $entityType, 'entityId' => $entityId, 'entityId' => $entityId, 'collectionKey' => $targetList, 'collectionKey' => $targetList, 'withPriority' => $withPriority, 'priority' => $priority->value, ]); ]); } } public static function bulkMarkEntitiesForUpdate( public static function bulkMarkEntitiesForUpdate( string $entityType, string $entityType, array $entityIds, array $entityIds, bool $withPriority = false QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): void { ): void { if (empty($entityIds)) { if (empty($entityIds)) { return; return; } } $targetList = self::selectTargetList($entityType, $withPriority); $targetList = self::selectTargetList($entityType, $priority); Redis::saddarray($targetList, $entityIds); Redis::saddarray($targetList, $entityIds); } } * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Expose the Redis list name, which holds the collection of scheduled entities to be processed. * Takes priority into consideration. * Takes priority into consideration. */ */ public static function getEntitiesSourceList(string $updateTarget, $priority = false): string public static function getEntitiesSourceList( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): string { return self::selectTargetList($updateTarget, $priority); return self::selectTargetList($updateTarget, $priority); } } /** /** * Externally called helper methods * Externally called helper methods * - count and flush * - count and flush */ */ public static function getEntitiesListCount(string $updateTarget, $priority = false): int public static function getEntitiesListCount( { string $updateTarget, QueuePriorityEnum $priority = QueuePriorityEnum::NORMAL ): int { $targetList = self::selectTargetList($updateTarget, $priority); $targetList = self::selectTargetList($updateTarget, $priority); return Redis::scard($targetList); return Redis::scard($targetList); app/Component/ES/QueuePriorityEnum.php +40Lines changed: 40 additions & 0 deletions Original file line numberOriginal file lineDiff line numberDiff line change <?php declare(strict_types=1); namespace Jiminny\Component\ES; use Jiminny\Exceptions\InvalidArgumentException; enum QueuePriorityEnum: string { case HIGH = 'high'; case NORMAL = 'normal'; case LOW = 'low'; public static function tryFromString(string $value): self { if (! self::isValid($value)) { throw new InvalidArgumentException( sprintf('Invalid queue priority "%s" selected', $value) ); } return self::tryFrom($value); } public static function isValid(string $value): bool { return self::tryFrom($value) !== null; } public function isLow(): bool { return $this === self::LOW; } public function isHigh(): bool { return $this === self::HIGH; } } app/Component/ES/UpdateProcessManager.php +12-9Lines changed: 12 additions & 9 deletions Original file line numberOriginal file lineDiff line numberDiff line change if ($selectionList->isEmpty()) { if ($selectionList->isEmpty()) { return false; return false; } } /** /** * A stale chunk will always be smaller than a regular chunk. * A stale chunk will always be smaller than a regular chunk. * That doesn't mean there aren't any other scheduled entities for processing * That doesn't mean there aren't any other scheduled entities for processing private function rescheduleThrottledEntities(SelectionList $selectionList): void private function rescheduleThrottledEntities(SelectionList $selectionList): void { { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $groups = $selectionList->getEntityListGroups(); $this->updateTarget, foreach ($groups as $eachGroup) { $selectionList->getNormalPriorityEntityId() $groupEntityIds = $selectionList->getEntityListItemsByGroup($eachGroup); ); if (! empty($groupEntityIds)) { AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate( $this->updateTarget, entityType: $this->updateTarget, $selectionList->getHighPriorityEntityIds(), entityIds: $groupEntityIds, true priority: QueuePriorityEnum::tryFromString($eachGroup) ); ); } } } } } } app/Console/Commands/Elasticsearch/AsyncUpdateEsEntities.php +9-3Lines changed: 9 additions & 3 deletions Original file line numberOriginal file lineDiff line numberDiff line changeuse Illuminate\Support\Str; use Illuminate\Support\Str; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\AsyncUpdateElasticSearch; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Component\ES\UpdateProcessManager; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; Redis::set($gaugeLockName, true); Redis::set($gaugeLockName, true); Redis::expire($gaugeLockName, 60); Redis::expire($gaugeLockName, 60); $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::HIGH), ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update', $updateTarget), stat: sprintf('jiminny.%s-for-update', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::NORMAL), ); ); $this->gaugeStats( $this->gaugeStats( stat: sprintf('jiminny.%s-for-update-priority', $updateTarget), stat: sprintf('jiminny.%s-for-update-low', $updateTarget), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, true), value: AsyncUpdateElasticSearch::getEntitiesListCount($updateTarget, QueuePriorityEnum::LOW), ); ); } } app/Console/Commands/Elasticsearch/ResetAsyncElasticSearchCommand.php +5-1Lines changed: 5 additions & 1 deletion Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\EntityQueryBuilder; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\Traits\ValidateUpdateTargetTrait; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\Processor\UpdateTarget; use Jiminny\Component\ES\QueuePriorityEnum; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Component\ES\Repositories\EsResetRepositoryInterface; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Exceptions\InvalidArgumentException; use Jiminny\Traits\GracefullyStoppable; use Jiminny\Traits\GracefullyStoppable; private function getRemainingScheduledEntities(bool $printStatus = false): int private function getRemainingScheduledEntities(bool $printStatus = false): int { { $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingRegular = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount($this->updateTarget, true); $remainingPriority = AsyncUpdateElasticSearch::getEntitiesListCount( $this->updateTarget, QueuePriorityEnum::HIGH ); if ($printStatus) { if ($printStatus) { $this->line( $this->line(
You said
app/Component/ES/Listeners/UpdateMultipleTargetsListener.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changenamespace Jiminny\Component\ES\Listeners;
namespace Jiminny\Component\ES\Listeners;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Jiminny\Contracts\ES\Events\UpdateMultipleEntities;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
AsyncUpdateElasticSearch::bulkMarkEntitiesForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntities(),
$event->getEntities(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
}
}
app/Component/ES/Listeners/UpdateSingleTargetListener.php
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\Actions\TrackElasticSearchOperations;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\AsyncUpdateElasticSearch;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\Processor\EntityQueryBuilder;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Jiminny\Contracts\ES\Events\UpdateSingleEntity;
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerInterface;
'entityId' => $event->getEntityId(),
'entityId' => $event->getEntityId(),
]);
]);
/**
* @important:
* Synchronous event should eventually be deprecated.
* Instant write operations are blocking and should be used sparingly.
* It is much better in terms of performance to write 100 or 1000 documents at once,
* and have one blocking reindex operation, instead of writing 10 documents synchronously.
*/
if ($event->isSyncEvent()) {
if ($event->isSyncEvent()) {
$this->handleSyncEvent($event);
$this->handleSyncEvent($event);
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
$event->getUpdateTargetValue(),
$event->getUpdateTargetValue(),
$event->getEntityId(),
$event->getEntityId(),
$event->isPriority()
$event->isPriority() ? QueuePriorityEnum::HIGH : QueuePriorityEnum::NORMAL,
);
);
}
}
app/Component/ES/Processor/Actions/UpsertDocumentsAction.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line changeuse Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\ResponseEvaluator;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\Processor\Traits\UpdateTargetTrait;
use Jiminny\Component\ES\QueuePriorityEnum;
use Jiminny\Exceptions\InvalidDataException;
use Jiminny\Exceptions\InvalidDataException;
use Sentry\Laravel\Facade as Sentry;
use Sentry\Laravel\Facade as Sentry;
AsyncUpdateElasticSearch::markEntityForUpdate(
AsyncUpdateElasticSearch::markEntityForUpdate(
entityType: $this->updateTarget,
entityType: $this->updateTarget,
entityId: (int) $document->getId(),
entityId: (int) $document->getId(),
withPriority: true
priority: QueuePriorityEnum::HIGH,
);
);
}
}
app/Component/ES/Processor/DTOs/SelectionList.php
+54-17Lines changed: 54 additions & 17 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
namespace Jiminny\Component\ES\Processor\DTOs;
namespace Jiminny\Component\ES\Processor\DTOs;
use Jiminny\Component\ES\QueuePriorityEnum;
/**
/**
* A very basic and simple collection of entity IDs.
* A very basic and simple collection of entity IDs.
*/
*/
class SelectionList
class SelectionList
{
{
public function __construct(
private const int DEFAULT_CHUNK = 200;
private readonly array $priorityEntityIdList = [],
private readonly array $normalEntityIdList = [],
private int $chunkSize = self::DEFAULT_CHUNK;
private readonly bool $isStaleChunkSelected = false,
private bool $isStaleChunkSelected = false;
private readonly int $chunkSize = 200,
private array $selectedEntityIds = [];
) {
// Do nothing
public function setChunkSize(int $chunkSize): void
{
$this->chunkSize = $chunkSize;
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55660
|
NULL
|
0
|
2026-05-19T06:36:33.989578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172593989_m2.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.15674867,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.1245012,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.15163608,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.35854387,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.37051198,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.3678524,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08494016,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09823803,"top":0.10454908,"width":0.028590426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.1008976,"top":0.10973663,"width":0.021941489,"height":0.020351157},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.33992687,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.35322472,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Are there any issues or potential bolltenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Are there any issues or potential bolltenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-3080295626791821589
|
8165139447676957079
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or...
|
55658
|
NULL
|
NULL
|
NULL
|
|
55659
|
NULL
|
0
|
2026-05-19T06:36:33.989578+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172593989_m1.jpg...
|
Firefox
|
JY-20808 low priority indexing queue by Vasil-Jimi JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app — Work...
|
1
|
github.com/jiminny/app/pull/12082/changes#diff-4bd github.com/jiminny/app/pull/12082/changes#diff-4bdd02759b5e0d060dcbc8c2dcb9bdbc3d0266d9c2e29956b9d63916dae1fdd7...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;5namespace Tests\\Unit\\Component\\ES\\Processor\\DTOs;667use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;7use Jiminny\\Component\\ES\\Processor\\DTOs\\SelectionList;8+use Jiminny\\Component\\ES\\QueuePriorityEnum;8use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\Attributes\\CoversClass;9use PHPUnit\\Framework\\TestCase;10use PHPUnit\\Framework\\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a precise and concise summary of the code selection, which refactors","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionListTest","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Refactored Priority Handling","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refactored Priority Handling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dynamic Priority Groups:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaces fixed high/normal array parameters with the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QueuePriorityEnum","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"HIGH","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NORMAL","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LOW","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), allowing entity lists to be managed dynamically by group types.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Merged Registrations:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Validates that multiple","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"calls targeting the same priority level properly merge their data instead of overwriting it.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group Querying:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests new methods","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListItemsByGroup()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"getEntityListGroups()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to retrieve group-specific IDs or an array of active group names (e.g.,","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"['high', 'normal']","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Updated State and Count Validations","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated State and Count Validations","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instantiation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tests now instantiate","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"without initial constructor arguments, using setters and action methods instead.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Empty States:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updates assertions (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isEmpty()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stale Flags:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes from passing a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stale","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"boolean via the constructor to explicitly triggering a mutable","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$selectionList->markStale()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Chunk Capacity Behavior","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Chunk Capacity Behavior","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Flexible Chunk Sizes:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method, replacing the constructor-configured chunk boundary.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Capacity Assertions:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Retains and updates the logic for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"isFullChunk()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said Are there any issues or potential bolltenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Are there any issues or potential bolltenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here are the potential issues and bottlenecks to consider:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Array Merging Overhead (Performance)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Array Merging Overhead (Performance)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"testAddEntityListMergesMultipleCallsForSamePriority","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"test shows that calling","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"multiple times for the same priority group merges the arrays.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the underlying implementation uses","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_merge()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ensure the implementation handles batch appends efficiently (e.g., using the spread operator","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[...$existing, ...$new]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or appending via references) or groups the arrays before doing a single merge.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. Lack of Uniqueness/Deduplication (Logic)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [1, 2])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and then","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"addEntityList(QueuePriorityEnum::HIGH, [2, 3])","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Issue:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Does the getter return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"or","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[1, 2, 3]","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The underlying class should ideally enforce uniqueness (e.g., using","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array_unique()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3. Memory Consumption with Large Chunks (Scalability)","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The tests introduce","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"setChunkSize()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":". If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Bottleneck:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SelectionList","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"object is kept alive during a long-running daemon or cron job.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mitigation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Monitor memory usage if","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"grows, and ensure the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4510348526296732241
|
8165667213393097111
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
JY-20808 low priority indexing queue by Vasil-Jiminny · Pull Request #12082 · jiminny/app
Close tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>JY-20808 low priority indexing queue by Vasil-Jimi</tabTitle>” with “<selection>@@ -5,84 +5,140 @@5namespace Tests\Unit\Component\ES\Processor\DTOs;5namespace Tests\Unit\Component\ES\Processor\DTOs;667use Jiminny\Component\ES\Processor\DTOs\SelectionList;7use Jiminny\Component\ES\Processor\DTOs\SelectionList;8+use Jiminny\Component\ES\QueuePriorityEnum;8use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\Attributes\CoversClass;9use PHPUnit\Framework\TestCase;10use PHPUnit\Framework\TestCase;101111#[CoversClass(SelectionList::class)]12#[CoversClass(SelectionList::class)]12final class SelectionListTest extends TestCase13final class SelectionListTest extends TestCase13{14{14-public function testGetEntityIds(): void15+private const int CHUNK_SIZE = 100;16+17+public function testAddEntityListAndGetAllIds(): void18+ {19+$selectionList = new SelectionList();20+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);21+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);22+23+$this->assertSame([1, 2, 3, 4], $selectionList->getAllIds());24+ }25+26+public function testAddEntityListMergesMultipleCallsForSamePriority(): void27+ {28+$selectionList = new SelectionList();29+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);30+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [3, 4]);31+32+$this->assertSame([1, 2, 3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));33+ }34+35+public function testGetEntityListItemsByGroup(): void36+ {37+$selectionList = new SelectionList();38+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1, 2]);39+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [3, 4]);40+$selectionList->addEntityList(QueuePriorityEnum::LOW, [5, 6]);41+42+$this->assertSame([1, 2], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));43+$this->assertSame([3, 4], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::NORMAL));44+$this->assertSame([5, 6], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::LOW));45+ }46+47+public function testGetEntityListItemsByGroupReturnsEmptyArrayForUnknownGroup(): void15 {48 {16-$priority = ['p1', 'p2'];49+$selectionList = new SelectionList();17-$normal = ['n1', 'n2'];50+18-$selectionList = new SelectionList($priority, $normal);51+$this->assertSame([], $selectionList->getEntityListItemsByGroup(QueuePriorityEnum::HIGH));52+ }195320-$this->assertSame($priority, $selectionList->getHighPriorityEntityIds());54+public function testGetEntityListGroups(): void21-$this->assertSame($normal, $selectionList->getNormalPriorityEntityId());55+ {56+$selectionList = new SelectionList();57+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);58+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2]);225923-$this->assertSame(['p1', 'p2', 'n1', 'n2'], $selectionList->getAllIds());60+$this->assertSame(['high', 'normal'], $selectionList->getEntityListGroups());24 }61 }256226public function testCountReturnsTotalCount(): void63public function testCountReturnsTotalCount(): void27 {64 {28-$selectionList = new SelectionList(['p1'], ['n1', 'n2']);65+$selectionList = new SelectionList();66+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);67+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [2, 3]);68+29$this->assertSame(3, $selectionList->count());69$this->assertSame(3, $selectionList->count());30 }70 }317132-public function testIsEmptyReturnsTrueWhenBothListsAreEmpty(): void72+public function testIsEmptyReturnsTrueWhenNoEntitiesAdded(): void33 {73 {34-$selectionList = new SelectionList([], []);74+$selectionList = new SelectionList();75+35$this->assertTrue($selectionList->isEmpty());76$this->assertTrue($selectionList->isEmpty());36 }77 }377838-public function testIsEmptyReturnsFalseWhenAnyListIsNotEmpty(): void79+public function testIsEmptyReturnsFalseWhenEntitiesAdded(): void39 {80 {40-$selectionList = new SelectionList(['p1'], []);81+$selectionList = new SelectionList();41-$this->assertFalse($selectionList->isEmpty());82+$selectionList->addEntityList(QueuePriorityEnum::HIGH, [1]);428343-$selectionList2 = new SelectionList([], ['n1']);84+$this->assertFalse($selectionList->isEmpty());44-$this->assertFalse($selectionList2->isEmpty());45 }85 }468647-public function testIsStaleChunkSelected(): void87+public function testMarkStaleAndIsStaleChunkSelected(): void48 {88 {49-$selectionList = new SelectionList([], [], true);89+$selectionList = new SelectionList();50-$this->assertTrue($selectionList->isStaleChunkSelected());90+91+$this->assertFalse($selectionList->isStaleChunkSelected());92+93+$selectionList->markStale();519452-$selectionList2 = new SelectionList([], [], false);95+$this->assertTrue($selectionList->isStaleChunkSelected());53-$this->assertFalse($selectionList2->isStaleChunkSelected());54 }96 }559756public function testIsFullChunk(): void98public function testIsFullChunk(): void57 {99 {58-$chunkSize = 200;100+$selectionList = new SelectionList();59-101+$selectionList->setChunkSize(self::CHUNK_SIZE);60-$fullList = range(1, $chunkSize);102+61-$selectionList = new SelectionList(103+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, self::CHUNK_SIZE));62- priorityEntityIdList: $fullList,104+63- normalEntityIdList: [],105+$this->assertTrue($selectionList->isFullChunk());64- chunkSize: $chunkSize,106+ }65- );107+108+public function testIsNotFullChunkWhenBelowChunkSize(): void109+ {110+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);111+112+$selectionList = new SelectionList();113+$selectionList->setChunkSize(self::CHUNK_SIZE);114+115+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range(1, $halfRange));116+117+$this->assertFalse($selectionList->isFullChunk());118+ }119+120+public function testIsFullChunkAcrossMultiplePriorityGroups(): void121+ {122+$halfRange = (int) ceil(self::CHUNK_SIZE / 2);123+124+$selectionList = new SelectionList();125+$selectionList->setChunkSize(self::CHUNK_SIZE);126+127+$selectionList->addEntityList(QueuePriorityEnum::HIGH, range(1, $halfRange));128+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, range($halfRange + 1, self::CHUNK_SIZE));129+130+$this->assertTrue($selectionList->isFullChunk());131+ }132+133+public function testSetChunkSizeAffectsIsFullChunk(): void134+ {135+$selectionList = new SelectionList();136+$selectionList->addEntityList(QueuePriorityEnum::NORMAL, [1, 2, 3]);137+138+$selectionList->setChunkSize(3);66$this->assertTrue($selectionList->isFullChunk());139$this->assertTrue($selectionList->isFullChunk());6714068-$halfRange = (int) ceil($chunkSize / 2);141+$selectionList->setChunkSize(50);69-142+$this->assertFalse($selectionList->isFullChunk());70-$notFullList = range(1, $halfRange);71-$selectionList2 = new SelectionList(72- priorityEntityIdList: $notFullList,73- normalEntityIdList: [],74- chunkSize: $chunkSize,75- );76-$this->assertFalse($selectionList2->isFullChunk());77-78-$priorityRange = range(1, $halfRange);79-$normalRange = range($halfRange + 1, $chunkSize);80-81-$selectionList3 = new SelectionList(82- priorityEntityIdList: $priorityRange,83- normalEntityIdList: $normalRange,84- chunkSize: $chunkSize,85- );86-$this->assertTrue($selectionList3->isFullChunk());87 }143 }88}144}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
Here is a precise and concise summary of the code selection, which refactors
SelectionListTest
to accommodate a shift from fixed high/normal priority properties to a more dynamic, enum-driven priority group architecture.
Refactored Priority Handling
Refactored Priority Handling
Dynamic Priority Groups:
Replaces fixed high/normal array parameters with the
QueuePriorityEnum
(
HIGH
,
NORMAL
,
LOW
), allowing entity lists to be managed dynamically by group types.
Merged Registrations:
Validates that multiple
addEntityList()
calls targeting the same priority level properly merge their data instead of overwriting it.
Group Querying:
Tests new methods
getEntityListItemsByGroup()
and
getEntityListGroups()
to retrieve group-specific IDs or an array of active group names (e.g.,
['high', 'normal']
).
Updated State and Count Validations
Updated State and Count Validations
Instantiation:
Tests now instantiate
SelectionList
without initial constructor arguments, using setters and action methods instead.
Empty States:
Updates assertions (
isEmpty()
) to verify state based on whether any entities have been dynamically added, rather than checking pre-defined constructor arrays.
Stale Flags:
Changes from passing a
stale
boolean via the constructor to explicitly triggering a mutable
$selectionList->markStale()
method.
Chunk Capacity Behavior
Chunk Capacity Behavior
Flexible Chunk Sizes:
Introduces a
setChunkSize()
method, replacing the constructor-configured chunk boundary.
Capacity Assertions:
Retains and updates the logic for
isFullChunk()
, ensuring it accurately evaluates capacity when elements span multiple dynamic priority groups or when the chunk limit is altered mid-lifecycle.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said Are there any issues or potential bolltenecks
You said
Are there any issues or potential bolltenecks
Listen
Show thinking
Gemini said
Gemini said
Based on the test diff you provided, we can infer a few potential issues and architectural bottlenecks in the underlying
SelectionList
implementation. While the tests are well-structured, the behavior they describe hints at a few areas you might want to keep an eye on, particularly for an Elasticsearch (ES) processor queue.
Here are the potential issues and bottlenecks to consider:
1. Array Merging Overhead (Performance)
1. Array Merging Overhead (Performance)
The
testAddEntityListMergesMultipleCallsForSamePriority
test shows that calling
addEntityList()
multiple times for the same priority group merges the arrays.
The Bottleneck:
If the underlying implementation uses
array_merge()
inside a loop to append these IDs, it creates a new array in memory every time it's called. If you are processing thousands of entities and appending them in small batches, this can lead to memory bloat and CPU degradation due to constant array reallocation.
Mitigation:
Ensure the implementation handles batch appends efficiently (e.g., using the spread operator
[...$existing, ...$new]
or appending via references) or groups the arrays before doing a single merge.
2. Lack of Uniqueness/Deduplication (Logic)
2. Lack of Uniqueness/Deduplication (Logic)
None of the tests explicitly verify what happens if duplicate IDs are added. For example, if you call
addEntityList(QueuePriorityEnum::HIGH, [1, 2])
and then
addEntityList(QueuePriorityEnum::HIGH, [2, 3])
.
The Issue:
Does the getter return
[1, 2, 2, 3]
or
[1, 2, 3]
? If duplicates are not filtered out, your ES processor might end up indexing the same entity multiple times in a single chunk, which wastes I/O and processor cycles.
Mitigation:
The underlying class should ideally enforce uniqueness (e.g., using
array_unique()
before resolving the chunk, or using ID keys as associative array keys to naturally prevent duplicates).
3. Memory Consumption with Large Chunks (Scalability)
3. Memory Consumption with Large Chunks (Scalability)
The tests introduce
setChunkSize()
. If this chunk size is configured to be very large (e.g., tens of thousands of IDs to bulk-send to Elasticsearch).
The Bottleneck:
Holding massive arrays of IDs in memory across different priority groups can quickly hit PHP memory limits, especially if this
SelectionList
object is kept alive during a long-running daemon or cron job.
Mitigation:
Monitor memory usage if
CHUNK_SIZE
grows, and ensure the...
|
55657
|
NULL
|
NULL
|
NULL
|
|
55624
|
NULL
|
0
|
2026-05-19T06:31:37.703347+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172297703_m2.jpg...
|
Firefox
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira — Work...
|
1
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20725...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
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...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.05905826,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.118914604,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"bounds":{"left":0.10887633,"top":0.057861134,"width":0.029421542,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"bounds":{"left":0.40475398,"top":0.06264964,"width":0.24268617,"height":0.015961692},"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"bounds":{"left":0.65575135,"top":0.057861134,"width":0.030086435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"bounds":{"left":0.66705453,"top":0.06384677,"width":0.014793883,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"bounds":{"left":0.91223407,"top":0.057861134,"width":0.035904255,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"bounds":{"left":0.92353725,"top":0.06384677,"width":0.020611702,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"1 Notification","depth":13,"bounds":{"left":0.9494681,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Notification","depth":15,"bounds":{"left":0.954621,"top":0.06344773,"width":0.028590426,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"bounds":{"left":0.96143615,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"bounds":{"left":0.9665891,"top":0.06344773,"width":0.010139627,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"bounds":{"left":0.9734042,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":15,"bounds":{"left":0.97855717,"top":0.06344773,"width":0.017952127,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"bounds":{"left":0.98537236,"top":0.057861134,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"bounds":{"left":0.99052525,"top":0.06344773,"width":0.009474754,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"bounds":{"left":0.08361037,"top":0.09976058,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"bounds":{"left":0.09424867,"top":0.10574621,"width":0.01662234,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"bounds":{"left":0.08361037,"top":0.12529927,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":16,"bounds":{"left":0.09424867,"top":0.13128492,"width":0.015458777,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"bounds":{"left":0.08361037,"top":0.15083799,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":16,"bounds":{"left":0.09424867,"top":0.15682362,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"bounds":{"left":0.08361037,"top":0.1763767,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":16,"bounds":{"left":0.09424867,"top":0.18236233,"width":0.011635638,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"bounds":{"left":0.15309176,"top":0.17956904,"width":0.0039893617,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"bounds":{"left":0.08361037,"top":0.2019154,"width":0.071476065,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"bounds":{"left":0.09424867,"top":0.20790103,"width":0.016456118,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"bounds":{"left":0.13646941,"top":0.20510775,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create space","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-1790291043589952781
|
4671299896740967556
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
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...
|
55622
|
NULL
|
NULL
|
NULL
|
|
55623
|
NULL
|
0
|
2026-05-19T06:31:37.699349+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779172297699_m1.jpg...
|
Firefox
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira — Work...
|
1
|
jiminny.atlassian.net/jira/software/c/projects/JY/ jiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedIssue=JY-20725...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
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...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Sidebar","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sidebar","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Main Content","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Main Content","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Space navigation","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Space navigation","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse sidebar [","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Collapse sidebar [","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Switch sites or apps","depth":11,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Switch sites or apps","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Go to your Jira homepage","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"Search, press enter to navigate to advanced search with your text query","depth":12,"on_screen":true,"help_text":"","placeholder":"Search","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Create","depth":11,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Create","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Rovo Ask Rovo","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Rovo","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"1 Notification","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 Notification","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Help","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Help","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Settings","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Settings","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"lukas.kovalik@jiminny.com","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas.kovalik@jiminny.com","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"For you","depth":13,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"For you","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recent","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Recent","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Starred","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Starred","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Apps","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Apps","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"More actions for Apps","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More actions for Apps","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Spaces","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Spaces","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Create space","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-4885021907826347434
|
4671299896745161860
|
click
|
accessibility
|
NULL
|
Platform Sprint 4 Q2 - Platform Team - Scrum Board Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 4 Q2 - Platform Team - Scrum Board - Jira
Close tab
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Sidebar
Sidebar
Main Content
Main Content
Space navigation
Space navigation
Collapse sidebar [
Collapse sidebar [
Switch sites or apps
Switch sites or apps
Go to your Jira homepage
Search, press enter to navigate to advanced search with your text query
Create
Create
Rovo Ask Rovo
Ask Rovo
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...
|
55621
|
NULL
|
NULL
|
NULL
|
|
55620
|
NULL
|
0
|
2026-05-18T16:39:37.407695+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779122377407_m1.jpg...
|
iTerm2
|
-zsh
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon May 18 09:17:28 on ttys009
Poetry Last login: Mon May 18 09:17:28 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 ~ $ sp-stop
screenpipe stopped
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll
total 52912
drwx------+ 96 lukas staff 3072 18 May 18:03 .
drwxr-xr-x 5 root admin 160 23 Aug 2024 ..
-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding
-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store
drwx------+ 5 lukas staff 160 18 May 17:08 .Trash
drwx------ 5 lukas staff 160 1 Nov 2021 .aws
-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json
-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history
-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc
drwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito
drwx------@ 7 lukas staff 224 12 May 20:05 .cache
drwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude
-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json
drwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium
drwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer
drwx------ 17 lukas staff 544 12 May 20:05 .config
drwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue
drwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot
drwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor
drwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor
drwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona
drwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb
drwx------ 24 lukas staff 768 18 May 09:39 .docker
drwx------ 15 lukas staff 480 6 Jun 2023 .dropbox
drwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak
-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth
-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig
-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp
drwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon
drwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc
-rw------- 1 lukas staff 20 18 May 13:14 .lesshst
drwx------ 5 lukas staff 160 23 Dec 2024 .local
-rw------- 1 lukas staff 204 16 Mar 2024 .netrc
drwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp
-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history
-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer
drwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py
drwx------ 9 lukas staff 288 18 May 09:35 .npm
-rw------- 1 lukas staff 74 20 May 2024 .npmrc
drwx------ 32 lukas staff 1024 25 Jul 2025 .nvm
drwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman
-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile
-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history
drwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode
drwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe
drwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint
drwx------ 15 lukas staff 480 8 Aug 2025 .ssh
drwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit
drwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm
-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo
drwx------ 5 lukas staff 160 19 Jun 2023 .vscode
drwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared
drwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp
drwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm
drwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf
drwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn
-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc
-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump
-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171
-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile
-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy
-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave
-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save
-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees
-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history
drwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions
-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc
drwx------@ 9 lukas staff 288 20 Apr 20:55 Applications
drwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects
drwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV
drwx------@ 15 lukas staff 480 18 May 17:08 Desktop
drwx------@ 7 lukas staff 224 10 May 21:04 Documents
drwx------@ 66 lukas staff 2112 17 May 15:46 Downloads
drwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen
drwx------@ 112 lukas staff 3584 2 Dec 09:19 Library
drwx------ 7 lukas staff 224 12 Feb 2024 Movies
drwx------+ 5 lukas staff 160 25 Sep 2023 Music
drwx------+ 9 lukas staff 288 25 Sep 2023 Pictures
drwx------ 3 lukas staff 96 8 Nov 2021 Postman
drwx------+ 4 lukas staff 128 28 Oct 2021 Public
-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf
drwx------ 4 lukas staff 128 2 Jul 2023 Users
-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log
-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log
-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4
-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg
drwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)
drwx------ 16 lukas staff 512 3 Nov 2025 jiminny
drwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules
drwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast
-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin
-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh
-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 14961312
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .
drwx------+ 96 lukas staff 3072 18 May 18:03 ..
-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store
-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id
-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash
drwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data
-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite
-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm
-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log
-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log
-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log
-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log
-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log
-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log
-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log
-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log
-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh
-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak
-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2
drwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts
-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe
11G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:34:23] ========================================
[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:34:23] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
Screenpipe process: not running ✓
vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0
[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.
[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:35:38] ========================================
[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:35:38] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.
[2026-05-18 19:35:38] On macOS: pkill -f screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
DOCKER
Close Tab
DEV (-zsh)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon May 18 09:17:28 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 ~ $ sp-stop\nscreenpipe stopped\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll\ntotal 52912\ndrwx------+ 96 lukas staff 3072 18 May 18:03 .\ndrwxr-xr-x 5 root admin 160 23 Aug 2024 ..\n-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding\n-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store\ndrwx------+ 5 lukas staff 160 18 May 17:08 .Trash\ndrwx------ 5 lukas staff 160 1 Nov 2021 .aws\n-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json\n-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history\n-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc\ndrwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito\ndrwx------@ 7 lukas staff 224 12 May 20:05 .cache\ndrwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude\n-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json\ndrwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium\ndrwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer\ndrwx------ 17 lukas staff 544 12 May 20:05 .config\ndrwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue\ndrwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot\ndrwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor\ndrwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor\ndrwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona\ndrwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb\ndrwx------ 24 lukas staff 768 18 May 09:39 .docker\ndrwx------ 15 lukas staff 480 6 Jun 2023 .dropbox\ndrwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak\n-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth\n-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig\n-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp\ndrwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon\ndrwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc\n-rw------- 1 lukas staff 20 18 May 13:14 .lesshst\ndrwx------ 5 lukas staff 160 23 Dec 2024 .local\n-rw------- 1 lukas staff 204 16 Mar 2024 .netrc\ndrwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp\n-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history\n-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer\ndrwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py\ndrwx------ 9 lukas staff 288 18 May 09:35 .npm\n-rw------- 1 lukas staff 74 20 May 2024 .npmrc\ndrwx------ 32 lukas staff 1024 25 Jul 2025 .nvm\ndrwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman\n-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile\n-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history\ndrwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode\ndrwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe\ndrwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint\ndrwx------ 15 lukas staff 480 8 Aug 2025 .ssh\ndrwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit\ndrwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm\n-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo\ndrwx------ 5 lukas staff 160 19 Jun 2023 .vscode\ndrwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared\ndrwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp\ndrwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm\ndrwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf\ndrwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn\n-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc\n-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump\n-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171\n-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile\n-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy\n-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave\n-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save\n-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees\n-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history\ndrwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions\n-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc\ndrwx------@ 9 lukas staff 288 20 Apr 20:55 Applications\ndrwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects\ndrwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV\ndrwx------@ 15 lukas staff 480 18 May 17:08 Desktop\ndrwx------@ 7 lukas staff 224 10 May 21:04 Documents\ndrwx------@ 66 lukas staff 2112 17 May 15:46 Downloads\ndrwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen\ndrwx------@ 112 lukas staff 3584 2 Dec 09:19 Library\ndrwx------ 7 lukas staff 224 12 Feb 2024 Movies\ndrwx------+ 5 lukas staff 160 25 Sep 2023 Music\ndrwx------+ 9 lukas staff 288 25 Sep 2023 Pictures\ndrwx------ 3 lukas staff 96 8 Nov 2021 Postman\ndrwx------+ 4 lukas staff 128 28 Oct 2021 Public\n-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf\ndrwx------ 4 lukas staff 128 2 Jul 2023 Users\n-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log\n-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg\ndrwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)\ndrwx------ 16 lukas staff 512 3 Nov 2025 jiminny\ndrwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules\ndrwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast\n-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin\n-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh\n-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll\ntotal 14961312\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .\ndrwx------+ 96 lukas staff 3072 18 May 18:03 ..\n-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store\n-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id\n-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash\ndrwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data\n-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite\n-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm\n-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal\ndrwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes\n-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log\n-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log\n-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log\n-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log\n-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log\n-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log\n-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log\n-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log\n-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log\n-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log\n-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log\n-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log\n-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log\n-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh\n-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk\n-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak\n-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2\ndrwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts\n-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe \n 11G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:34:23] ========================================\n[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:34:23] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n Screenpipe process: not running ✓\n vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0\n[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.\n[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:35:38] ========================================\n[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:35:38] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.\n[2026-05-18 19:35:38] On macOS: pkill -f screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11","depth":4,"on_screen":true,"value":"Last login: Mon May 18 09:17:28 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 ~ $ sp-stop\nscreenpipe stopped\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll\ntotal 52912\ndrwx------+ 96 lukas staff 3072 18 May 18:03 .\ndrwxr-xr-x 5 root admin 160 23 Aug 2024 ..\n-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding\n-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store\ndrwx------+ 5 lukas staff 160 18 May 17:08 .Trash\ndrwx------ 5 lukas staff 160 1 Nov 2021 .aws\n-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json\n-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history\n-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc\ndrwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito\ndrwx------@ 7 lukas staff 224 12 May 20:05 .cache\ndrwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude\n-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json\ndrwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium\ndrwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer\ndrwx------ 17 lukas staff 544 12 May 20:05 .config\ndrwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue\ndrwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot\ndrwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor\ndrwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor\ndrwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona\ndrwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb\ndrwx------ 24 lukas staff 768 18 May 09:39 .docker\ndrwx------ 15 lukas staff 480 6 Jun 2023 .dropbox\ndrwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak\n-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth\n-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig\n-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp\ndrwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon\ndrwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc\n-rw------- 1 lukas staff 20 18 May 13:14 .lesshst\ndrwx------ 5 lukas staff 160 23 Dec 2024 .local\n-rw------- 1 lukas staff 204 16 Mar 2024 .netrc\ndrwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp\n-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history\n-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer\ndrwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py\ndrwx------ 9 lukas staff 288 18 May 09:35 .npm\n-rw------- 1 lukas staff 74 20 May 2024 .npmrc\ndrwx------ 32 lukas staff 1024 25 Jul 2025 .nvm\ndrwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman\n-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile\n-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history\ndrwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode\ndrwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe\ndrwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint\ndrwx------ 15 lukas staff 480 8 Aug 2025 .ssh\ndrwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit\ndrwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm\n-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo\ndrwx------ 5 lukas staff 160 19 Jun 2023 .vscode\ndrwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared\ndrwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp\ndrwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm\ndrwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf\ndrwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn\n-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc\n-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump\n-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171\n-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile\n-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy\n-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave\n-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save\n-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees\n-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history\ndrwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions\n-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc\ndrwx------@ 9 lukas staff 288 20 Apr 20:55 Applications\ndrwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects\ndrwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV\ndrwx------@ 15 lukas staff 480 18 May 17:08 Desktop\ndrwx------@ 7 lukas staff 224 10 May 21:04 Documents\ndrwx------@ 66 lukas staff 2112 17 May 15:46 Downloads\ndrwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen\ndrwx------@ 112 lukas staff 3584 2 Dec 09:19 Library\ndrwx------ 7 lukas staff 224 12 Feb 2024 Movies\ndrwx------+ 5 lukas staff 160 25 Sep 2023 Music\ndrwx------+ 9 lukas staff 288 25 Sep 2023 Pictures\ndrwx------ 3 lukas staff 96 8 Nov 2021 Postman\ndrwx------+ 4 lukas staff 128 28 Oct 2021 Public\n-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf\ndrwx------ 4 lukas staff 128 2 Jul 2023 Users\n-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log\n-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg\ndrwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)\ndrwx------ 16 lukas staff 512 3 Nov 2025 jiminny\ndrwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules\ndrwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast\n-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin\n-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh\n-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll\ntotal 14961312\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .\ndrwx------+ 96 lukas staff 3072 18 May 18:03 ..\n-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store\n-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id\n-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash\ndrwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data\n-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite\n-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm\n-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal\ndrwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes\n-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log\n-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log\n-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log\n-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log\n-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log\n-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log\n-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log\n-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log\n-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log\n-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log\n-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log\n-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log\n-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log\n-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh\n-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk\n-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak\n-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2\ndrwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts\n-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe \n 11G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:34:23] ========================================\n[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:34:23] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n Screenpipe process: not running ✓\n vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0\n[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.\n[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:35:38] ========================================\n[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:35:38] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.\n[2026-05-18 19:35:38] On macOS: pkill -f screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.0,"top":0.05888889,"width":0.19826388,"height":0.026666667},"on_screen":true,"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},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (-zsh)","depth":2,"bounds":{"left":0.19826388,"top":0.05888889,"width":0.19826388,"height":0.026666667},"on_screen":true,"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.20243056,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"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.39652777,"top":0.05888889,"width":0.19791667,"height":0.026666667},"on_screen":true,"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.40069443,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.59444445,"top":0.05888889,"width":0.19791667,"height":0.026666667},"on_screen":true,"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.5986111,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.79236114,"top":0.05888889,"width":0.19791667,"height":0.026666667},"on_screen":true,"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.7965278,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.9618056,"top":0.032222223,"width":0.038194418,"height":0.018888889},"on_screen":true,"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.49166667,"top":0.033333335,"width":0.022916667,"height":0.017777778},"on_screen":true,"role_description":"text"}]...
|
3506116863957964289
|
7525118544404479585
|
visual_change
|
accessibility
|
NULL
|
Last login: Mon May 18 09:17:28 on ttys009
Poetry Last login: Mon May 18 09:17:28 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 ~ $ sp-stop
screenpipe stopped
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll
total 52912
drwx------+ 96 lukas staff 3072 18 May 18:03 .
drwxr-xr-x 5 root admin 160 23 Aug 2024 ..
-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding
-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store
drwx------+ 5 lukas staff 160 18 May 17:08 .Trash
drwx------ 5 lukas staff 160 1 Nov 2021 .aws
-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json
-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history
-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc
drwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito
drwx------@ 7 lukas staff 224 12 May 20:05 .cache
drwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude
-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json
drwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium
drwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer
drwx------ 17 lukas staff 544 12 May 20:05 .config
drwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue
drwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot
drwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor
drwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor
drwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona
drwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb
drwx------ 24 lukas staff 768 18 May 09:39 .docker
drwx------ 15 lukas staff 480 6 Jun 2023 .dropbox
drwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak
-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth
-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig
-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp
drwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon
drwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc
-rw------- 1 lukas staff 20 18 May 13:14 .lesshst
drwx------ 5 lukas staff 160 23 Dec 2024 .local
-rw------- 1 lukas staff 204 16 Mar 2024 .netrc
drwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp
-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history
-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer
drwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py
drwx------ 9 lukas staff 288 18 May 09:35 .npm
-rw------- 1 lukas staff 74 20 May 2024 .npmrc
drwx------ 32 lukas staff 1024 25 Jul 2025 .nvm
drwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman
-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile
-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history
drwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode
drwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe
drwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint
drwx------ 15 lukas staff 480 8 Aug 2025 .ssh
drwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit
drwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm
-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo
drwx------ 5 lukas staff 160 19 Jun 2023 .vscode
drwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared
drwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp
drwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm
drwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf
drwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn
-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc
-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump
-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171
-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile
-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy
-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave
-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save
-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees
-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history
drwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions
-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc
drwx------@ 9 lukas staff 288 20 Apr 20:55 Applications
drwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects
drwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV
drwx------@ 15 lukas staff 480 18 May 17:08 Desktop
drwx------@ 7 lukas staff 224 10 May 21:04 Documents
drwx------@ 66 lukas staff 2112 17 May 15:46 Downloads
drwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen
drwx------@ 112 lukas staff 3584 2 Dec 09:19 Library
drwx------ 7 lukas staff 224 12 Feb 2024 Movies
drwx------+ 5 lukas staff 160 25 Sep 2023 Music
drwx------+ 9 lukas staff 288 25 Sep 2023 Pictures
drwx------ 3 lukas staff 96 8 Nov 2021 Postman
drwx------+ 4 lukas staff 128 28 Oct 2021 Public
-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf
drwx------ 4 lukas staff 128 2 Jul 2023 Users
-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log
-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log
-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4
-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg
drwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)
drwx------ 16 lukas staff 512 3 Nov 2025 jiminny
drwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules
drwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast
-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin
-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh
-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 14961312
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .
drwx------+ 96 lukas staff 3072 18 May 18:03 ..
-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store
-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id
-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash
drwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data
-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite
-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm
-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log
-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log
-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log
-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log
-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log
-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log
-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log
-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log
-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh
-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak
-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2
drwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts
-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe
11G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:34:23] ========================================
[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:34:23] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
Screenpipe process: not running ✓
vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0
[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.
[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:35:38] ========================================
[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:35:38] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.
[2026-05-18 19:35:38] On macOS: pkill -f screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
DOCKER
Close Tab
DEV (-zsh)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
55618
|
NULL
|
NULL
|
NULL
|
|
55619
|
NULL
|
0
|
2026-05-18T16:39:34.907262+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779122374907_m2.jpg...
|
iTerm2
|
-zsh
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon May 18 09:17:28 on ttys009
Poetry Last login: Mon May 18 09:17:28 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 ~ $ sp-stop
screenpipe stopped
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll
total 52912
drwx------+ 96 lukas staff 3072 18 May 18:03 .
drwxr-xr-x 5 root admin 160 23 Aug 2024 ..
-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding
-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store
drwx------+ 5 lukas staff 160 18 May 17:08 .Trash
drwx------ 5 lukas staff 160 1 Nov 2021 .aws
-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json
-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history
-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc
drwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito
drwx------@ 7 lukas staff 224 12 May 20:05 .cache
drwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude
-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json
drwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium
drwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer
drwx------ 17 lukas staff 544 12 May 20:05 .config
drwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue
drwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot
drwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor
drwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor
drwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona
drwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb
drwx------ 24 lukas staff 768 18 May 09:39 .docker
drwx------ 15 lukas staff 480 6 Jun 2023 .dropbox
drwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak
-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth
-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig
-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp
drwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon
drwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc
-rw------- 1 lukas staff 20 18 May 13:14 .lesshst
drwx------ 5 lukas staff 160 23 Dec 2024 .local
-rw------- 1 lukas staff 204 16 Mar 2024 .netrc
drwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp
-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history
-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer
drwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py
drwx------ 9 lukas staff 288 18 May 09:35 .npm
-rw------- 1 lukas staff 74 20 May 2024 .npmrc
drwx------ 32 lukas staff 1024 25 Jul 2025 .nvm
drwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman
-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile
-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history
drwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode
drwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe
drwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint
drwx------ 15 lukas staff 480 8 Aug 2025 .ssh
drwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit
drwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm
-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo
drwx------ 5 lukas staff 160 19 Jun 2023 .vscode
drwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared
drwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp
drwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm
drwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf
drwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn
-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc
-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump
-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171
-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile
-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy
-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave
-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save
-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees
-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history
drwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions
-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc
drwx------@ 9 lukas staff 288 20 Apr 20:55 Applications
drwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects
drwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV
drwx------@ 15 lukas staff 480 18 May 17:08 Desktop
drwx------@ 7 lukas staff 224 10 May 21:04 Documents
drwx------@ 66 lukas staff 2112 17 May 15:46 Downloads
drwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen
drwx------@ 112 lukas staff 3584 2 Dec 09:19 Library
drwx------ 7 lukas staff 224 12 Feb 2024 Movies
drwx------+ 5 lukas staff 160 25 Sep 2023 Music
drwx------+ 9 lukas staff 288 25 Sep 2023 Pictures
drwx------ 3 lukas staff 96 8 Nov 2021 Postman
drwx------+ 4 lukas staff 128 28 Oct 2021 Public
-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf
drwx------ 4 lukas staff 128 2 Jul 2023 Users
-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log
-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log
-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4
-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg
drwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)
drwx------ 16 lukas staff 512 3 Nov 2025 jiminny
drwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules
drwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast
-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin
-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh
-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 14961312
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .
drwx------+ 96 lukas staff 3072 18 May 18:03 ..
-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store
-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id
-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash
drwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data
-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite
-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm
-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log
-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log
-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log
-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log
-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log
-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log
-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log
-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log
-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh
-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak
-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2
drwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts
-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe
11G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:34:23] ========================================
[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:34:23] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
Screenpipe process: not running ✓
vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0
[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.
[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:35:38] ========================================
[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:35:38] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.
[2026-05-18 19:35:38] On macOS: pkill -f screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $
DOCKER
Close Tab
DEV (-zsh)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon May 18 09:17:28 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 ~ $ sp-stop\nscreenpipe stopped\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll\ntotal 52912\ndrwx------+ 96 lukas staff 3072 18 May 18:03 .\ndrwxr-xr-x 5 root admin 160 23 Aug 2024 ..\n-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding\n-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store\ndrwx------+ 5 lukas staff 160 18 May 17:08 .Trash\ndrwx------ 5 lukas staff 160 1 Nov 2021 .aws\n-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json\n-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history\n-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc\ndrwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito\ndrwx------@ 7 lukas staff 224 12 May 20:05 .cache\ndrwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude\n-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json\ndrwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium\ndrwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer\ndrwx------ 17 lukas staff 544 12 May 20:05 .config\ndrwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue\ndrwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot\ndrwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor\ndrwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor\ndrwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona\ndrwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb\ndrwx------ 24 lukas staff 768 18 May 09:39 .docker\ndrwx------ 15 lukas staff 480 6 Jun 2023 .dropbox\ndrwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak\n-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth\n-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig\n-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp\ndrwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon\ndrwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc\n-rw------- 1 lukas staff 20 18 May 13:14 .lesshst\ndrwx------ 5 lukas staff 160 23 Dec 2024 .local\n-rw------- 1 lukas staff 204 16 Mar 2024 .netrc\ndrwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp\n-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history\n-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer\ndrwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py\ndrwx------ 9 lukas staff 288 18 May 09:35 .npm\n-rw------- 1 lukas staff 74 20 May 2024 .npmrc\ndrwx------ 32 lukas staff 1024 25 Jul 2025 .nvm\ndrwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman\n-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile\n-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history\ndrwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode\ndrwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe\ndrwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint\ndrwx------ 15 lukas staff 480 8 Aug 2025 .ssh\ndrwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit\ndrwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm\n-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo\ndrwx------ 5 lukas staff 160 19 Jun 2023 .vscode\ndrwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared\ndrwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp\ndrwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm\ndrwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf\ndrwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn\n-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc\n-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump\n-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171\n-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile\n-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy\n-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave\n-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save\n-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees\n-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history\ndrwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions\n-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc\ndrwx------@ 9 lukas staff 288 20 Apr 20:55 Applications\ndrwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects\ndrwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV\ndrwx------@ 15 lukas staff 480 18 May 17:08 Desktop\ndrwx------@ 7 lukas staff 224 10 May 21:04 Documents\ndrwx------@ 66 lukas staff 2112 17 May 15:46 Downloads\ndrwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen\ndrwx------@ 112 lukas staff 3584 2 Dec 09:19 Library\ndrwx------ 7 lukas staff 224 12 Feb 2024 Movies\ndrwx------+ 5 lukas staff 160 25 Sep 2023 Music\ndrwx------+ 9 lukas staff 288 25 Sep 2023 Pictures\ndrwx------ 3 lukas staff 96 8 Nov 2021 Postman\ndrwx------+ 4 lukas staff 128 28 Oct 2021 Public\n-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf\ndrwx------ 4 lukas staff 128 2 Jul 2023 Users\n-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log\n-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg\ndrwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)\ndrwx------ 16 lukas staff 512 3 Nov 2025 jiminny\ndrwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules\ndrwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast\n-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin\n-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh\n-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll\ntotal 14961312\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .\ndrwx------+ 96 lukas staff 3072 18 May 18:03 ..\n-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store\n-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id\n-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash\ndrwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data\n-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite\n-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm\n-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal\ndrwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes\n-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log\n-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log\n-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log\n-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log\n-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log\n-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log\n-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log\n-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log\n-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log\n-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log\n-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log\n-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log\n-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log\n-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh\n-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk\n-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak\n-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2\ndrwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts\n-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe \n 11G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:34:23] ========================================\n[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:34:23] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n Screenpipe process: not running ✓\n vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0\n[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.\n[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:35:38] ========================================\n[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:35:38] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.\n[2026-05-18 19:35:38] On macOS: pkill -f screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $","depth":4,"on_screen":true,"value":"Last login: Mon May 18 09:17:28 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 ~ $ sp-stop\nscreenpipe stopped\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll\ntotal 52912\ndrwx------+ 96 lukas staff 3072 18 May 18:03 .\ndrwxr-xr-x 5 root admin 160 23 Aug 2024 ..\n-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding\n-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store\ndrwx------+ 5 lukas staff 160 18 May 17:08 .Trash\ndrwx------ 5 lukas staff 160 1 Nov 2021 .aws\n-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json\n-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history\n-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc\ndrwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito\ndrwx------@ 7 lukas staff 224 12 May 20:05 .cache\ndrwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude\n-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json\ndrwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium\ndrwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer\ndrwx------ 17 lukas staff 544 12 May 20:05 .config\ndrwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue\ndrwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot\ndrwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor\ndrwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor\ndrwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona\ndrwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb\ndrwx------ 24 lukas staff 768 18 May 09:39 .docker\ndrwx------ 15 lukas staff 480 6 Jun 2023 .dropbox\ndrwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak\n-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth\n-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig\n-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp\ndrwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon\ndrwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc\n-rw------- 1 lukas staff 20 18 May 13:14 .lesshst\ndrwx------ 5 lukas staff 160 23 Dec 2024 .local\n-rw------- 1 lukas staff 204 16 Mar 2024 .netrc\ndrwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp\n-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history\n-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer\ndrwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py\ndrwx------ 9 lukas staff 288 18 May 09:35 .npm\n-rw------- 1 lukas staff 74 20 May 2024 .npmrc\ndrwx------ 32 lukas staff 1024 25 Jul 2025 .nvm\ndrwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman\n-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile\n-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history\ndrwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode\ndrwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe\ndrwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint\ndrwx------ 15 lukas staff 480 8 Aug 2025 .ssh\ndrwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit\ndrwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm\n-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo\ndrwx------ 5 lukas staff 160 19 Jun 2023 .vscode\ndrwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared\ndrwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp\ndrwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm\ndrwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf\ndrwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn\n-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc\n-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump\n-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170\n-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171\n-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile\n-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy\n-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave\n-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save\n-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees\n-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history\ndrwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions\n-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc\ndrwx------@ 9 lukas staff 288 20 Apr 20:55 Applications\ndrwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects\ndrwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV\ndrwx------@ 15 lukas staff 480 18 May 17:08 Desktop\ndrwx------@ 7 lukas staff 224 10 May 21:04 Documents\ndrwx------@ 66 lukas staff 2112 17 May 15:46 Downloads\ndrwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen\ndrwx------@ 112 lukas staff 3584 2 Dec 09:19 Library\ndrwx------ 7 lukas staff 224 12 Feb 2024 Movies\ndrwx------+ 5 lukas staff 160 25 Sep 2023 Music\ndrwx------+ 9 lukas staff 288 25 Sep 2023 Pictures\ndrwx------ 3 lukas staff 96 8 Nov 2021 Postman\ndrwx------+ 4 lukas staff 128 28 Oct 2021 Public\n-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf\ndrwx------ 4 lukas staff 128 2 Jul 2023 Users\n-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log\n-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4\n-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg\ndrwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)\ndrwx------ 16 lukas staff 512 3 Nov 2025 jiminny\ndrwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules\ndrwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast\n-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin\n-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh\n-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe \nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll\ntotal 14961312\ndrwxr-xr-x 29 lukas staff 928 18 May 09:35 .\ndrwx------+ 96 lukas staff 3072 18 May 18:03 ..\n-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store\n-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id\n-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash\ndrwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data\n-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite\n-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm\n-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal\ndrwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes\n-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log\n-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log\n-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log\n-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log\n-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log\n-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log\n-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log\n-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log\n-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log\n-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log\n-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log\n-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log\n-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log\n-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh\n-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk\n-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak\n-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2\ndrwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts\n-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe \n 11G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:34:23] ========================================\n[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:34:23] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n Screenpipe process: not running ✓\n vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0\n[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.\n[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11\n[2026-05-18 19:35:38] ========================================\n[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11\n[2026-05-18 19:35:38] ========================================\n\n[+00m00s] ▶ Preflight checks\n DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)\n[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.\n[2026-05-18 19:35:38] On macOS: pkill -f screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.094913565,"height":-0.042298436},"on_screen":true,"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},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (-zsh)","depth":2,"bounds":{"left":0.36519283,"top":1.0,"width":0.094913565,"height":-0.042298436},"on_screen":true,"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.3671875,"top":1.0,"width":0.005319149,"height":-0.04549086},"on_screen":true,"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.46010637,"top":1.0,"width":0.09474734,"height":-0.042298436},"on_screen":true,"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.46210107,"top":1.0,"width":0.005319149,"height":-0.04549086},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.55485374,"top":1.0,"width":0.09474734,"height":-0.042298436},"on_screen":true,"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.5568484,"top":1.0,"width":0.005319149,"height":-0.04549086},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.64960104,"top":1.0,"width":0.09474734,"height":-0.042298436},"on_screen":true,"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.6515958,"top":1.0,"width":0.005319149,"height":-0.04549086},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.7307181,"top":1.0,"width":0.01861702,"height":-0.023144484},"on_screen":true,"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.5056516,"top":1.0,"width":0.010970744,"height":-0.02394259},"on_screen":true,"role_description":"text"}]...
|
-6067455792388705847
|
5219275535190785633
|
click
|
accessibility
|
NULL
|
Last login: Mon May 18 09:17:28 on ttys009
Poetry Last login: Mon May 18 09:17:28 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 ~ $ sp-stop
screenpipe stopped
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ll
total 52912
drwx------+ 96 lukas staff 3072 18 May 18:03 .
drwxr-xr-x 5 root admin 160 23 Aug 2024 ..
-r-------- 1 lukas staff 7 18 Nov 2021 .CFUserTextEncoding
-rw-r--r--@ 1 lukas staff 28676 18 May 09:17 .DS_Store
drwx------+ 5 lukas staff 160 18 May 17:08 .Trash
drwx------ 5 lukas staff 160 1 Nov 2021 .aws
-rw-r--r-- 1 lukas staff 341470 29 Sep 2022 .babel.json
-rw-------@ 1 lukas staff 388 25 Jul 2025 .bash_history
-rw-r--r--@ 1 lukas staff 115 18 Apr 13:19 .bashrc
drwxr-xr-x 5 lukas staff 160 11 Mar 2023 .bito
drwx------@ 7 lukas staff 224 12 May 20:05 .cache
drwxr-xr-x 22 lukas staff 704 11 May 16:38 .claude
-rw-------@ 1 lukas staff 29161 12 May 20:03 .claude.json
drwxr-xr-x@ 20 lukas staff 640 12 Mar 09:12 .codeium
drwxrwxrwx@ 3 lukas staff 96 2 Mar 2023 .composer
drwx------ 17 lukas staff 544 12 May 20:05 .config
drwxr-xr-x 15 lukas staff 480 23 Dec 2024 .continue
drwx------@ 3 lukas staff 96 16 Feb 19:13 .copilot
drwxr-xr-x@ 5 lukas staff 160 9 Apr 2025 .cursor
drwxr-xr-x@ 5 lukas staff 160 17 Aug 2024 .cursor-tutor
drwxr-xr-x 3 lukas staff 96 8 Sep 2024 .daytona
drwxr-xr-x@ 4 lukas staff 128 18 Feb 10:52 .devdb
drwx------ 24 lukas staff 768 18 May 09:39 .docker
drwx------ 15 lukas staff 480 6 Jun 2023 .dropbox
drwxr-xr-x@ 3 lukas staff 96 20 Nov 2022 .fig.dotfiles.bak
-rw-r--r-- 1 lukas staff 138 5 Mar 2022 .gauth
-rw-r--r-- 1 lukas staff 220 25 Nov 2021 .gitconfig
-rw-r--r-- 1 lukas staff 12288 25 Nov 2021 .gitconfig.swp
drwx------ 5 lukas staff 160 18 Nov 2021 .hammerspoon
drwxr-xr-x 3 lukas staff 96 21 Mar 2025 .idlerc
-rw------- 1 lukas staff 20 18 May 13:14 .lesshst
drwx------ 5 lukas staff 160 23 Dec 2024 .local
-rw------- 1 lukas staff 204 16 Mar 2024 .netrc
drwx------ 3 lukas staff 96 1 Nov 2021 .node-gyp
-rw------- 1 lukas staff 4 6 Feb 2024 .node_repl_history
-rw-r--r-- 1 lukas staff 17 24 Dec 2023 .notion-enhancer
drwxr-xr-x 4 lukas staff 128 12 Jul 2024 .notion-py
drwx------ 9 lukas staff 288 18 May 09:35 .npm
-rw------- 1 lukas staff 74 20 May 2024 .npmrc
drwx------ 32 lukas staff 1024 25 Jul 2025 .nvm
drwxr-xr-x 4 lukas staff 128 5 Aug 2023 .postman
-rw-r--r--@ 1 lukas staff 77 9 Feb 2023 .profile
-rw-------@ 1 lukas staff 3153 21 Mar 2025 .python_history
drwx------ 2 lukas staff 64 15 Nov 2021 .quicktype-vscode
drwxr-xr-x@ 8 lukas staff 256 16 Feb 08:48 .redis-insight
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .screenpipe
drwxr-xr-x 4 lukas staff 128 4 Feb 09:35 .sonarlint
drwx------ 15 lukas staff 480 8 Aug 2025 .ssh
drwxr-xr-x@ 3 lukas staff 96 15 Aug 2025 .streamlit
drwx------ 6 lukas staff 192 17 Oct 2022 .swiftpm
-rw------- 1 lukas staff 12133 18 May 13:09 .viminfo
drwx------ 5 lukas staff 160 19 Jun 2023 .vscode
drwxr-xr-x@ 3 lukas staff 96 8 May 20:21 .vscode-shared
drwxr-xr-x@ 3 lukas staff 96 20 Jan 2025 .warp
drwxr-xr-x 4 lukas staff 128 29 Apr 2023 .wdm
drwxr-xr-x@ 5 lukas staff 160 26 Jan 13:03 .windsurf
drwxr-xr-x 4 lukas staff 128 24 Mar 12:03 .yarn
-rw-r--r-- 1 lukas staff 116 30 Mar 10:12 .yarnrc
-rw-r--r-- 1 lukas staff 49518 12 May 20:12 .zcompdump
-rw-r--r--@ 1 lukas staff 46758 2 Nov 2025 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.23381
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25170
-rw-r--r--@ 1 lukas staff 35 12 May 20:05 .zcompdump.Lukas-Kovaliks-MacBook-Pro-Jiminny.25171
-rw-r--r--@ 1 lukas staff 6116 20 Apr 19:52 .zprofile
-rw-r--r-- 1 lukas staff 1468 8 Apr 2022 .zprofile-copy
-rw-r--r--@ 1 lukas staff 2900 15 Mar 2023 .zprofile.pysave
-rw------- 1 lukas staff 1731 29 Jun 2022 .zprofile.save
-rw-r--r-- 1 lukas staff 1569 8 Apr 2022 .zprofilees
-rw------- 1 lukas staff 32953 16 May 18:04 .zsh_history
drwx------ 9 lukas staff 288 6 May 2025 .zsh_sessions
-rw-r--r--@ 1 lukas staff 400 18 Apr 13:19 .zshrc
drwx------@ 9 lukas staff 288 20 Apr 20:55 Applications
drwxr-xr-x@ 2 lukas staff 64 22 Oct 2025 CascadeProjects
drwxr-xr-x 4 lukas staff 128 27 Oct 2025 DEV
drwx------@ 15 lukas staff 480 18 May 17:08 Desktop
drwx------@ 7 lukas staff 224 10 May 21:04 Documents
drwx------@ 66 lukas staff 2112 17 May 15:46 Downloads
drwxr-xr-x@ 4 lukas staff 128 17 Mar 20:27 Keychron_Screen
drwx------@ 112 lukas staff 3584 2 Dec 09:19 Library
drwx------ 7 lukas staff 224 12 Feb 2024 Movies
drwx------+ 5 lukas staff 160 25 Sep 2023 Music
drwx------+ 9 lukas staff 288 25 Sep 2023 Pictures
drwx------ 3 lukas staff 96 8 Nov 2021 Postman
drwx------+ 4 lukas staff 128 28 Oct 2021 Public
-rw-r--r--@ 1 lukas staff 3950 15 Dec 09:16 Untitled 4.spf
drwx------ 4 lukas staff 128 2 Jul 2023 Users
-rw-r--r-- 1 lukas staff 17050804 27 Apr 19:18 cleanshot-live.log
-rw-r--r-- 1 lukas staff 9363061 27 Apr 19:24 cleanshot-screenpipe.log
-rw-r--r-- 1 lukas staff 0 12 Apr 12:50 clip.mp4
-rw-r--r-- 1 lukas staff 0 12 Apr 12:51 frame.jpg
drwx------ 3 lukas staff 96 30 Sep 2022 iCloud Drive (Archive)
drwx------ 16 lukas staff 512 3 Nov 2025 jiminny
drwxr-xr-x 3 lukas staff 96 20 Mar 18:47 node_modules
drwxr-xr-x 4 lukas staff 128 21 Oct 2025 raycast
-rw-r--r-- 1 lukas staff 0 1 Mar 14:26 response.bin
-rwxr-xr-x 1 lukas staff 3824 11 Apr 15:16 screenpipe-day.sh
-rw-r--r-- 1 lukas staff 86 20 Mar 18:47 yarn.lock
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ cd ~/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ll
total 14961312
drwxr-xr-x 29 lukas staff 928 18 May 09:35 .
drwx------+ 96 lukas staff 3072 18 May 18:03 ..
-rw-r--r--@ 1 lukas staff 10244 16 May 16:46 .DS_Store
-rw-r--r--@ 1 lukas staff 37 11 May 20:54 .sync_install_id
-rw-r--r-- 1 lukas staff 0 10 May 14:43 clipboard-disabled-after-crash
drwxr-xr-x 6836 lukas staff 218752 18 May 18:03 data
-rw-r--r--@ 1 lukas staff 7639453696 18 May 18:02 db.sqlite
-rw-r--r-- 1 lukas staff 98304 18 May 10:25 db.sqlite-shm
-rw-r--r-- 1 lukas staff 16566552 18 May 18:03 db.sqlite-wal
drwxr-xr-x 9 lukas staff 288 10 May 11:39 pipes
-rw-r--r-- 1 lukas staff 8413 16 May 16:46 prune.log
-rw-r--r-- 1 lukas staff 28408 6 May 21:02 screenpipe.2026-05-06.0.log
-rw-r--r-- 1 lukas staff 566164 7 May 21:50 screenpipe.2026-05-07.0.log
-rw-r--r-- 1 lukas staff 382102 8 May 22:20 screenpipe.2026-05-08.0.log
-rw-r--r-- 1 lukas staff 167023 9 May 23:04 screenpipe.2026-05-09.0.log
-rw-r--r-- 1 lukas staff 88266 10 May 23:51 screenpipe.2026-05-10.0.log
-rw-r--r-- 1 lukas staff 528943 11 May 22:54 screenpipe.2026-05-11.0.log
-rw-r--r-- 1 lukas staff 294131 12 May 21:46 screenpipe.2026-05-12.0.log
-rw-r--r-- 1 lukas staff 449051 13 May 20:51 screenpipe.2026-05-13.0.log
-rw-r--r-- 1 lukas staff 319916 14 May 18:29 screenpipe.2026-05-14.0.log
-rw-r--r-- 1 lukas staff 201533 15 May 14:21 screenpipe.2026-05-15.0.log
-rw-r--r-- 1 lukas staff 24231 16 May 16:08 screenpipe.2026-05-16.0.log
-rw-r--r-- 1 lukas staff 297792 18 May 18:03 screenpipe.2026-05-18.0.log
-rwxr-xr-x@ 1 lukas staff 18401 12 May 21:28 screenpipe_sync.sh
-rwxr-xr-x@ 1 lukas staff 32005 11 May 20:54 screenpipe_sync.sh-bakk
-rwxr-xr-x@ 1 lukas staff 14994 6 May 20:26 screenpipe_sync.sh.bak
-rwxr-xr-x@ 1 lukas staff 21485 10 May 13:34 screenpipe_sync.sh.bak2
drwxr-xr-x 7 lukas staff 224 15 May 20:35 scripts
-rw-r--r--@ 1 lukas staff 113066 18 May 09:27 sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ du -sh ~/.screenpipe
11G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:34:23] ========================================
[2026-05-18 19:34:23] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:34:23] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
Screenpipe process: not running ✓
vec0 dylib: /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0
[2026-05-18 19:34:24] ERROR: sqlite3 CLI cannot load vec0 extension.
[2026-05-18 19:34:24] Test manually: echo '.load /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/sqlite_vec/vec0' | sqlite3 :memory:
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ ~/.screenpipe/scripts/screenpipe_prune_mac.sh 2026-05-11
[2026-05-18 19:35:38] ========================================
[2026-05-18 19:35:38] Mac prune starting — cutoff: < 2026-05-11
[2026-05-18 19:35:38] ========================================
[+00m00s] ▶ Preflight checks
DB: /Users/lukas/.screenpipe/db.sqlite (7.1G)
[2026-05-18 19:35:38] ERROR: Screenpipe appears to be running. Stop it first.
[2026-05-18 19:35:38] On macOS: pkill -f screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $ open .
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/.screenpipe $
DOCKER
Close Tab
DEV (-zsh)
Close Tab
APP (-zsh)
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
55617
|
NULL
|
NULL
|
NULL
|
|
55560
|
NULL
|
0
|
2026-05-18T15:03:27.395677+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779116607395_m1.jpg...
|
iTerm2
|
EU (ssh)
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpEU (ssh)DOCKER881DEV (-zsh)О $2X t1DOCKER (-zsh)"taskManager""taskManager"], "pid":7, "message""Failed to poll for work: Error: No Liconnections"}1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}I {"type" : "log", "@timestamp""2026-05-18T13:02:072""tags": ["warning"sticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch", "data"],"pid" :7,"message": "No livingconnections"}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager","plugi"taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type": "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error", "elasticsearch".,"data"],"pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana{"type":"log""@timestamp"2026-05-18T13:02:10Z""tags" : ["worning""elasticsearch", "data"], "pid" :7, "message"le to revive conhection:[URL_WITH_CREDENTIALS] "data"],"pid" :7,"message":"No living connections"}kibanans"1 {"type": "log","@timestamp": "2026-05-18T13:02:10Z"'tags'"':["'error", "plugi,"reporting", "esqueue", "queue-worker""error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}kibana1 {"type" : "1og", "@timestamp" : "2026-05-18T13:02:10Z" , "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z"sticsearch", "data"], "pid":7, "message" : "No livingconnections"}, "tags" : ["warning", "elakibana1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error"ns", "taskManager""taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: No Livingconnections"?kibana1 {"type" : "log","@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch: 9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $100% <78• Mon 18 May 18:03:27T81APP (-zsh)• *3T2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe*O $4PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)S[URL_WITH_CREDENTIALS] ~17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|FRONTENDEXTENSION...
|
NULL
|
-1363649056630754700
|
NULL
|
visual_change
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpEU (ssh)DOCKER881DEV (-zsh)О $2X t1DOCKER (-zsh)"taskManager""taskManager"], "pid":7, "message""Failed to poll for work: Error: No Liconnections"}1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}I {"type" : "log", "@timestamp""2026-05-18T13:02:072""tags": ["warning"sticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch", "data"],"pid" :7,"message": "No livingconnections"}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager","plugi"taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type": "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error", "elasticsearch".,"data"],"pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana{"type":"log""@timestamp"2026-05-18T13:02:10Z""tags" : ["worning""elasticsearch", "data"], "pid" :7, "message"le to revive conhection:[URL_WITH_CREDENTIALS] "data"],"pid" :7,"message":"No living connections"}kibanans"1 {"type": "log","@timestamp": "2026-05-18T13:02:10Z"'tags'"':["'error", "plugi,"reporting", "esqueue", "queue-worker""error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}kibana1 {"type" : "1og", "@timestamp" : "2026-05-18T13:02:10Z" , "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z"sticsearch", "data"], "pid":7, "message" : "No livingconnections"}, "tags" : ["warning", "elakibana1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error"ns", "taskManager""taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: No Livingconnections"?kibana1 {"type" : "log","@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch: 9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $100% <78• Mon 18 May 18:03:27T81APP (-zsh)• *3T2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe*O $4PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)S[URL_WITH_CREDENTIALS] ~17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|FRONTENDEXTENSION...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55559
|
NULL
|
0
|
2026-05-18T15:03:19.011111+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779116599011_m2.jpg...
|
Boosteroid
|
Boosteroid
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
AGEEMPIRESRETURNROMEAGEEMPIRESDEFINITIVE EDITIONKO AGEEMPIRESRETURNROMEAGEEMPIRESDEFINITIVE EDITIONKOVALIKLUKASNot signed into Xbox NetworkSINGLE PLAYERLEARN TO PLAYCo-OP CAMPAIGNSMULTIPLAYEREDITORSMODSEXITVERSION 101.103.44206.0 (#175[PHONE]5...
|
NULL
|
1188967422572439405
|
NULL
|
visual_change
|
ocr
|
NULL
|
AGEEMPIRESRETURNROMEAGEEMPIRESDEFINITIVE EDITIONKO AGEEMPIRESRETURNROMEAGEEMPIRESDEFINITIVE EDITIONKOVALIKLUKASNot signed into Xbox NetworkSINGLE PLAYERLEARN TO PLAYCo-OP CAMPAIGNSMULTIPLAYEREDITORSMODSEXITVERSION 101.103.44206.0 (#175[PHONE]5...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55484
|
NULL
|
0
|
2026-05-18T14:20:13.974171+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779114013974_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <8• Mon 1 FinderFileEditViewGoWindowHelp‹$0100% <8• Mon 18 May 17:20:13EU (ssh)DOCKER881DEV (-zsh)О $2X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"],"pid":7,to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z" , "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","plugi,"reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe"0 84PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ I17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|FRONTENDEXTENSION...
|
NULL
|
-342192033574332926
|
NULL
|
visual_change
|
ocr
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <8• Mon 1 FinderFileEditViewGoWindowHelp‹$0100% <8• Mon 18 May 17:20:13EU (ssh)DOCKER881DEV (-zsh)О $2X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"],"pid":7,to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z" , "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","plugi,"reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe"0 84PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ I17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|FRONTENDEXTENSION...
|
55483
|
NULL
|
NULL
|
NULL
|
|
55482
|
NULL
|
0
|
2026-05-18T14:20:10.699224+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779114010699_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario Georgiev.. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…Tonislav Atanasov (D...Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...000 VworkNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2Mon 18 May 17:20:10-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GBMPEG-4 movie698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
6150582501390703781
|
NULL
|
idle
|
ocr
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario Georgiev.. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…Tonislav Atanasov (D...Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...000 VworkNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2Mon 18 May 17:20:10-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GBMPEG-4 movie698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55474
|
NULL
|
0
|
2026-05-18T14:18:19.189975+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113899189_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <78• Mon FinderFileEditViewGoWindowHelp‹$0100% <78• Mon 18 May 17:18:18EU (ssh)DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"], "pid"to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe*884PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
NULL
|
5563115857073982047
|
NULL
|
visual_change
|
ocr
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <78• Mon FinderFileEditViewGoWindowHelp‹$0100% <78• Mon 18 May 17:18:18EU (ssh)DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"], "pid"to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.screenpipe*884PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
55473
|
NULL
|
NULL
|
NULL
|
|
55471
|
NULL
|
0
|
2026-05-18T14:18:06.539986+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113886539_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario GeorgievP. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…… Tonislav Atanasov (D....Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...000 VworkNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2Mon 18 May 17:18:06-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 GB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GBMPEG-4 movie698.5 M:1,16 GBMPEG-4 movie1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
8395367826400874003
|
NULL
|
idle
|
ocr
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario GeorgievP. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…… Tonislav Atanasov (D....Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...000 VworkNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2Mon 18 May 17:18:06-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 GB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GBMPEG-4 movie698.5 M:1,16 GBMPEG-4 movie1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55448
|
NULL
|
0
|
2026-05-18T14:13:14.078643+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113594078_m1.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0EU (ssh)100% < FinderFileEditViewGoWindowHelp‹$0EU (ssh)100% <78• Mon 18 May 17:13:13screenpipe*DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"], "pid"to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"],"pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
NULL
|
-7364841130328192017
|
NULL
|
visual_change
|
ocr
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0EU (ssh)100% < FinderFileEditViewGoWindowHelp‹$0EU (ssh)100% <78• Mon 18 May 17:13:13screenpipe*DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"], "pid"to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"],"pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning""elasticsearch", "data"],"pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
55447
|
NULL
|
NULL
|
NULL
|
|
55445
|
NULL
|
0
|
2026-05-18T14:12:57.782337+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113577782_m2.jpg...
|
iTerm2
|
NULL
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario Georgiev.. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…Tonislav Atanasov (D...Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...workNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2?.Mon 18 May 17:12:57-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GB698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
-3361663589897878148
|
NULL
|
idle
|
ocr
|
NULL
|
HomeActivitySlackcalVIewJiminny …..v# platform-tic HomeActivitySlackcalVIewJiminny …..v# platform-tickets# product_launchesac random# releases# sofia-office# support# thank-yous# the_people_of_jimi..•? Direct messagesP. Aneliya AngelovaRR. Nikolay Yankova. Stefka Stoyanova8. Stoyan Tomov€. Vasil VasilevP. Galya Dimitrova OCa Todor Stamatov 998. Mario Georgiev.. Nikolay Ivanov2o James Graham 7R. Stoyan TanevR. Steliyan Georgievf Petko Kashinski. Lukas Kovalik y...i: AppsG Jira Cloud® ToastMistonWindowhelp@ Describe what you are looking for& . Aneliya Angelova• Messagest Add canvasMorev• опоавих гоToday~прооваи сьщия тестd 1Aneliva Angelova 5:08 PMизглежла всичко е ок вечеуспях да получа този warning 12026-05-18 14:06:53] qai.WARNING: [Hubspot]Received 42y trom AP("team_id":1052,"config_id":980,"retry_after"•1."reason" "Client error' "POS]ihttps://api.hubapi.com/crm/v3/objects/contact/search resulted in a 429 00 ManvRequests response:inamam enpop-uи матчинга слел warninga пролължиnuos:/us-east-.console.aws.amazon.com/cloudwatch/home.region=us-east-2#logsvilogs-insights$3FqueryDetail$l..JntlDs~~AlD~quervbv~'all LogGrouos.Lukas Kovalik 5:10 PMcynenутре ше го деплоина тогаваd 1Message Aneliya Angelova+ Aa €= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ Resolvertextfields ~ "Resolver*"actor transcription providers flowck iT a transcription mode is allowed berore usina it as overrideoader • create a new olattorm tor uoloaded callsnove supportChannelDiarization method and use track channelsw dialer soecitic rules tor particioanis creationJsers must finish onboarding to be able to use the dialerVetine ana conticure dara pavioaasnolement sott-deletion of transcriotion model locale entries.Assianee& UnassignedUnassianedIlian KyuchukovKaloyan Nikolov (Dea…Tonislav Atanasov (D...Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...workNamev 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Dailv 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4Du Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mn/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4• Refinement 2026-02-09-converted.mo4P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M9 Mer G0nG At 40:15100% 2?.Mon 18 May 17:12:57-- Folder4,05 GB982 MBMPEG-4 movie737.7 MBIMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CB1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GB698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MB MPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA MAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55411
|
NULL
|
0
|
2026-05-18T14:08:14.928841+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113294928_m2.jpg...
|
Finder
|
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
rindel+ Work item search - JiraService-Desk - Queu rindel+ Work item search - JiraService-Desk - Queues - Platfornw Usage | WindsurfAllow owner's role to be selectedPipelines - jiminny/appN1 (SRD-6848] Sidekick SMS issue -CloudWatch I us-east-2CloudWatch | us-east-28 Jiminnys) Jiminny\Exceptions|SocialAccountAllow owner's role to be selectedU (SRD-68621 'User does not have al* New Tab(JY-209121 Fallback mechanism fcS MIY-207711 Call Scorina filter for &(UY-20878] SCIM > Allow customel- WJY-208791 Enable users to use thProject Phoenix - Figma(UY-20847] Users can filter ScoresLIY-205341 Al Call Scorina quick al- New TabF1 109m 14cl405 GRWindowMelpO JIMINNY@ For you(• Recent# Starred0+ Apps|Q Spaces+ ***Jiminny (New)ul Planorm leamIID Capture TeamID Enterprise Stability I…..IN Processing TeamMl SE KanbanC Service-Desk= More spaces= Filters1 Q Search work items— ast commentedi= My tickets= (SRD)— Dialers & CRM Team > ...~ Nefault filterc I= My open work items= Reported by me= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ ResolverAll work* Ask AIBasictextfields ~ "Resolver*"JY-16891 Refactor transcription providers flow+ JY-14913 Check if a transcription mode is allowed before using it as overrideW JY-12384 Uoloader > create a new olattorm tor uoloaded callsO JY-11338 Remove supportChannelDiarization method and use track channelsN JY-10b// Allow dialer soecitic rules tor particioanis creationA JMNY-6785 Users must finish onboarding to be able to use the dialerO JMNY-3404 Define and configure data payloads9 JMNY-3112 Imolement soft-deletion of transcriotion model locale entriesAssianee& UnassignedUnassianedIlian KyuchukovKaloyan Niolo ve....… Tonislav Atanasov (D....Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...workv N 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4• Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4# Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Daily 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4D Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4= Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mo/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4= Refinement 2026-02-09-converted.mo4)P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M Mer G0nG At 40.45100% S2?.Mon 18 May 17:08:14-- Folder4,05 GB982 MBMPEG-4 movie737.7 MEMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CBMPEG-4 movie1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GB698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MBMPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie2.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA mAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
-5263983381542696646
|
NULL
|
idle
|
ocr
|
NULL
|
rindel+ Work item search - JiraService-Desk - Queu rindel+ Work item search - JiraService-Desk - Queues - Platfornw Usage | WindsurfAllow owner's role to be selectedPipelines - jiminny/appN1 (SRD-6848] Sidekick SMS issue -CloudWatch I us-east-2CloudWatch | us-east-28 Jiminnys) Jiminny\Exceptions|SocialAccountAllow owner's role to be selectedU (SRD-68621 'User does not have al* New Tab(JY-209121 Fallback mechanism fcS MIY-207711 Call Scorina filter for &(UY-20878] SCIM > Allow customel- WJY-208791 Enable users to use thProject Phoenix - Figma(UY-20847] Users can filter ScoresLIY-205341 Al Call Scorina quick al- New TabF1 109m 14cl405 GRWindowMelpO JIMINNY@ For you(• Recent# Starred0+ Apps|Q Spaces+ ***Jiminny (New)ul Planorm leamIID Capture TeamID Enterprise Stability I…..IN Processing TeamMl SE KanbanC Service-Desk= More spaces= Filters1 Q Search work items— ast commentedi= My tickets= (SRD)— Dialers & CRM Team > ...~ Nefault filterc I= My open work items= Reported by me= All work items= Open work items= Done work items= Viewed recently= Created recently= Resolved recentlv= Updated recently= View all filters( DashboardsC: Operations& ConfluenceQ ResolverAll work* Ask AIBasictextfields ~ "Resolver*"JY-16891 Refactor transcription providers flow+ JY-14913 Check if a transcription mode is allowed before using it as overrideW JY-12384 Uoloader > create a new olattorm tor uoloaded callsO JY-11338 Remove supportChannelDiarization method and use track channelsN JY-10b// Allow dialer soecitic rules tor particioanis creationA JMNY-6785 Users must finish onboarding to be able to use the dialerO JMNY-3404 Define and configure data payloads9 JMNY-3112 Imolement soft-deletion of transcriotion model locale entriesAssianee& UnassignedUnassianedIlian KyuchukovKaloyan Niolo ve....… Tonislav Atanasov (D....Дg Nikola Petkanski (Dea...& UnassignedJames GranamiReporterTonravountesE jiminny(* AirDrop• RecentsA ApplicationsDocuments© Downloadsii lukasiCloud• iCloud Drive999 Svnc toldelLocationsO DXP4800PLUS-B5F A® Network• CRM• Orange• Red• Yellov• Green• Blue• PurpleO All Tags...workv N 2026Refinement 2026-05-18.mp4# Dally 2026-05-18.mp4BE Chapter 2026-05-15 (Claude Code).mp4* Daily 2026-05-15.mp4: Daily 2026-05-14.mp4F™ Pannina 2026-04-15.mo4Ra Planning 2026-05-13.mp4• Retro 2026-05-12.mp4# Daily 2026-05-12.mp4= PLanhat Petko interest event 2026-05-11.mp4* Daily 2026-05-11.mp4* Daily 2026-00-08.mp4т 1-12026-05-07 mo4# Daily 2026-05-07.mp41-1 2026-04-24.mp4=: Daily 2026-04-24.mp4m User Pilot introduction Adi 2026-04-23.mp4Daily 2026-04-23.mp4Daily 2026-04-22.mp4gm Refinement 2026-04-06.mp4- Daily 2026-04-21.mp4D Refinement 2026-04-20.mp4Daily 2026-04-17.mp4Fu Daily 2026-04-16.mp 4Retro 2026-04-14.mp4Daily 2026-04-14 mn/= User pilot (Adi) 2026-04-09.mp4- Daily 2026-04-09.mp4wa Dailv 2026-04-08.mo4a Daily 2026-04-07.mp4= Dallv 2026-04-03,mo4aw Planning 2026-04-01 & task split.mp4wn: Retro 2026-03-31.mp4- Daily 2026-03-31.mp4Refinement 2026-03-30.mo4m Daily 2026-03-30.mp4Daily 2026-03-27.mp4• Dallv 2026-03-26.m04E Daily 2026-02-21 mn/- Refinennent 2026-03-23.mp4= Daily 2026-03-23.mp4•= RE chanter 2026-03.20.mo/- Daily 2026-03-20.mp4n Planing 2026-03-18-converted.mp4= Refinement 2026-02-09-converted.mo4)P:n Daily 2026.02-10 mn/- Review 2026-03-18.mp4am Planing 2026-03-18.mp4Retro 2026-02-17mnd- Daily 2026-03-17.mp4- Refinement 2026-03-16.mp4• Dailv 2026-03-16.mo4Dailv 2026-03-13.m04Date ModifiedToday at 17:06Today at 10:1315 Mav 2026 at 10:5415 May 2026 at 10:0213 May 2026 at 13:0913 May 2026 at 10:5112 May 2026 at 17:3612 May 2026 at 10:1311 May 2026 at 12:228 May 2026 at 10:227 Mav 2026 at 18:217 May 2026 at 10:1024 Apr 2026 at 14:4424 Aor 2026 at 10:1123 Apr 2026 at 11:5822 Apr 2026 at 10:2121 Anr 2026 at 11:0221 Apr 2026 at 10:0020 Apr 2026 at 16:5620 Aor 2026 at 10:0617 Apr 2026 at 10:1614 Apr 2026 at 17:3714 Anr 2026 at 10:009 Apr 2026 at 14:479 Apr 2026 at 10:078 Aor 2026 at 10:167 Apr 2026 at 10:016 Apr 2026 at 10:083Aor 2026 at 10.211 Anr 2026 at 12:2031 Mar 2026 at 18:2931 Mar 2026 at 10:1030 Mar 2026 at 17:1230 Mar 2026 at 10:0527 Mar 2026 at 10:0926 Mar 2026 at 9:5924 Mar 2026 at 10:0023 Mar 2026 at 17:0323 Mar 2026 at 10:0020 Mar 2026 at 11:4620 Mar 2026 at 10:0619 Mar 2026 at 12:0119 Mar 2026 at 11:3510 Mar 2026 at 0:5718 Mar 2026 at 16:2018 Mar 2026 at 11:1417 Mar 2026 at 17:40.17 Mar 2026 at 10:1816 Mar 2026 at 10:02M Mer G0nG At 40.45100% S2?.Mon 18 May 17:08:14-- Folder4,05 GB982 MBMPEG-4 movie737.7 MEMPEG-4 movie557,5 MBMPEG-4 movie968,5 MB MPEG-4 movie2.79 G:MPEG-4 movie1,87 GB MPEG-4 movie1,03 GB1.02 GEMPEG-4 movie1145MR MDEG-A movid491,3 MBMPEG-4 movie1,37 GBMPEG-4 movie1.55 G:MPEG-4 movie931,7 MB MPEG-4 movie1,86 GB832.2 MBMPEG-4 movie724 MBMPEG-4 movie1,74 CBMPEG-4 movie1,36 GBMPEG-4 movie241 G:MPEG-A movid567,8 MBMPEG-4 movie4,25 GB698.5 M:1,16 GBMPEG-4 movie513,4 MB1,44 GBMPEG-4 movie024 AMPMDEG-A movie362,6 MBMPEG-4 movie748,8 MB1.04 G:MPEG-4 movie575,5 MBMPEG-4 movie1.02 G:MPEG-4 movieA6R GPMDEG-A movid3,4 GBMPEG-4 movie923,6 MBMPEG-4 movie2.77 GE641,8 MB MPEG-4 movie476,6 M:MPEG-4 movie550 9 MPMDSG-A movie3,44 GBMPEG-4 movie438,9 MB1.68 GEMPEG.A movid430,4 MB MPEG-4 movie2,38 GB MPEG-4 movie2.26 GEMPEG-4 movie296 2 MRMDEG.A movid705,8 MBMPEG-4 movie2,78 GBMPEG-4 movie1.53 GPMPEG-A movie1,2 GB MPEG-4 movie4,19 GB592.2 ME1nn CoMPEG-4 movieMDEeA mAvid1 of 162 selected, 7.88 TB available...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55410
|
NULL
|
0
|
2026-05-18T14:07:48.877381+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779113268877_m1.jpg...
|
Finder
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <78• Mon FinderFileEditViewGoWindowHelp‹$0100% <78• Mon 18 May 17:07:48EU (ssh)DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"],"pid":7,to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"], "pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","plugi,"reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.ffmpeg0 84PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
NULL
|
5446105733094254024
|
NULL
|
idle
|
ocr
|
NULL
|
FinderFileEditViewGoWindowHelp‹$0100% <78• Mon FinderFileEditViewGoWindowHelp‹$0100% <78• Mon 18 May 17:07:48EU (ssh)DOCKER881DEV (-zsh)O $82X t1DOCKER (-zsh)"taskManager"connections"}"taskManager"],"pid":7,to poll for work: Error: No Li1 {"type":"log", "@timestamp" : "2026-05-18T13:02:06Z","tags" : ["error""pid":7, "message": "[ConnectionError]: getaddrinfoENOTFOUND elasticsearch elasticsearch:9200"}{"type" : "log","@timestamp":"2026-05-18T13:02:07Z""tags": ["warning"sticsearch", "data"], "pid" :7,revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T13:02:07Z", "tags" : ["warning", "elasticsearch","data"], "pid":7,"message":"No livingconnections "}kibanans"1 {"type" : "log""@timestamp": "2026-05-18T13:02:07Z""tags" : ["error""taskManager""taskManager"], "pid":7, "message": "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T13:02:08Z", "tags" : ["error"icsearch".,"elast,"data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana, "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["warning""elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z" , "tags" : ["warning"sticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type": "log", "@timestamp": "2026-05-18T13:02:10Z""tags" : ["error","plugi,"reporting", "esqueue", "queue-worker","error"], "pid" :7, "message" : "mpau4y7h00070bdf8646mdeo - job querying failed: Error: No Living connections\nat sendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}1 {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T13:02:10Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibana1 {"type" : "log",, "@timestamp" : "2026-05-18T13:02:10Z""tags": ["error"ns", "taskManager", "taskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T13:02:10Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T13:02:11Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $APP (-zsh)• *3t2PROD (ssh)'do-release-upgrade' to upgrade to it.ffmpeg0 84PROD*** System restart required ***Last login: Thu May 14 07:41:36 2026 from 212.5.153.87lukas@jiminny-prod-bastion:~$X T3 EU (ssh)Enable ESM Apps to receive additional future security updates.See [URL_WITH_CREDENTIALS] STAGE (ssh)See [URL_WITH_CREDENTIALS] ~ $ IFRONTENDPoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|EXTENSION...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55352
|
NULL
|
0
|
2026-05-18T14:02:59.496729+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779112979496_m2.jpg...
|
Finder
|
DXP4800PLUS-B5F
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
Name
Date Modified
Size
Kind
Connecting…
Connect As…
0 items
DXP4800PLUS-B5F...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Favourites","depth":6,"bounds":{"left":0.5046542,"top":0.061452515,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"jiminny","depth":6,"bounds":{"left":0.51263297,"top":0.08140463,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"AirDrop","depth":6,"bounds":{"left":0.51263297,"top":0.103751,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Recents","depth":6,"bounds":{"left":0.51263297,"top":0.12609737,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Applications","depth":6,"bounds":{"left":0.51263297,"top":0.14844373,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Documents","depth":6,"bounds":{"left":0.51263297,"top":0.1707901,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Downloads","depth":6,"bounds":{"left":0.51263297,"top":0.19313647,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lukas","depth":6,"bounds":{"left":0.51263297,"top":0.21548285,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"iCloud","depth":6,"bounds":{"left":0.5046542,"top":0.2434158,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"iCloud Drive","depth":6,"bounds":{"left":0.51263297,"top":0.26336792,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sync folder","depth":6,"bounds":{"left":0.51263297,"top":0.2857143,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Locations","depth":6,"bounds":{"left":0.5046542,"top":0.31364724,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":6,"bounds":{"left":0.51263297,"top":0.33359936,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Network","depth":6,"bounds":{"left":0.51263297,"top":0.35594574,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tags","depth":6,"bounds":{"left":0.5046542,"top":0.38387868,"width":0.06216755,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"CRM","depth":6,"bounds":{"left":0.51263297,"top":0.4038308,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Orange","depth":6,"bounds":{"left":0.51263297,"top":0.42617717,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Red","depth":6,"bounds":{"left":0.51263297,"top":0.44852355,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Yellow","depth":6,"bounds":{"left":0.51263297,"top":0.4708699,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Green","depth":6,"bounds":{"left":0.51263297,"top":0.49321628,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Blue","depth":6,"bounds":{"left":0.51263297,"top":0.51556265,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Purple","depth":6,"bounds":{"left":0.51263297,"top":0.53790903,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"All Tags…","depth":6,"bounds":{"left":0.51263297,"top":0.5602554,"width":0.049534574,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Name","depth":7,"bounds":{"left":0.5827792,"top":0.08858739,"width":0.011968086,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Date Modified","depth":7,"bounds":{"left":0.8656915,"top":0.08858739,"width":0.025930852,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Size","depth":7,"bounds":{"left":0.92586434,"top":0.08858739,"width":0.008976064,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kind","depth":7,"bounds":{"left":0.9581117,"top":0.08858739,"width":0.00930851,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Name","depth":6,"bounds":{"left":0.5711436,"top":0.083798885,"width":0.29288563,"height":0.022346368},"on_screen":true,"role_description":"sort button","subrole":"AXSortButton","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Date Modified","depth":6,"bounds":{"left":0.8640292,"top":0.083798885,"width":0.06017287,"height":0.022346368},"on_screen":true,"role_description":"sort button","subrole":"AXSortButton","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Size","depth":6,"bounds":{"left":0.92420214,"top":0.083798885,"width":0.032247342,"height":0.022346368},"on_screen":true,"role_description":"sort button","subrole":"AXSortButton","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Kind","depth":6,"bounds":{"left":0.95644945,"top":0.083798885,"width":0.040226065,"height":0.022346368},"on_screen":true,"role_description":"sort button","subrole":"AXSortButton","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Connecting…","depth":2,"bounds":{"left":0.57081115,"top":0.06624102,"width":0.02825798,"height":0.011971269},"on_screen":true,"automation_id":"_NS:10","role_description":"text"},{"role":"AXButton","text":"Connect As…","depth":2,"bounds":{"left":0.9684175,"top":0.065442935,"width":0.027925532,"height":0.015163607},"on_screen":true,"automation_id":"_NS:38","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"0 items","depth":2,"bounds":{"left":0.77360374,"top":0.98324025,"width":0.016954787,"height":0.011173184},"on_screen":true,"automation_id":"_NS:34","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":1,"bounds":{"left":0.5990692,"top":0.019952115,"width":0.14378324,"height":0.0415004},"on_screen":true,"role_description":"text"}]...
|
-5489754960907684982
|
-1839682751017496682
|
visual_change
|
accessibility
|
NULL
|
Favourites
jiminny
AirDrop
Recents
Applications
Do Favourites
jiminny
AirDrop
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Date Modified
Size
Kind
Name
Date Modified
Size
Kind
Connecting…
Connect As…
0 items
DXP4800PLUS-B5F...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55350
|
NULL
|
0
|
2026-05-18T14:02:57.845267+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779112977845_m1.jpg...
|
Finder
|
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Finder File•<→ CEdit View GoWindowHelp100% C47 Finder File•<→ CEdit View GoWindowHelp100% C47 8• Mon 18 May 17:02:57• =@ meet.google.com/cxs-eips-npt?authuser=lukas.kovalik%40jiminny.com(55)Returning to home screenYou left the meetingRejoinReturn to home screenHow was the audio and video?Very badVery good• Feedback...
|
NULL
|
2252365249669368265
|
NULL
|
visual_change
|
ocr
|
NULL
|
Finder File•<→ CEdit View GoWindowHelp100% C47 Finder File•<→ CEdit View GoWindowHelp100% C47 8• Mon 18 May 17:02:57• =@ meet.google.com/cxs-eips-npt?authuser=lukas.kovalik%40jiminny.com(55)Returning to home screenYou left the meetingRejoinReturn to home screenHow was the audio and video?Very badVery good• Feedback...
|
55349
|
NULL
|
NULL
|
NULL
|
|
55223
|
NULL
|
0
|
2026-05-18T13:57:51.571340+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779112671571_m1.jpg...
|
PhpStorm
|
faVsco.js – Crm/…/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
8
39
5
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Close;
use Cache;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CloseInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\ServiceUnavailableException;
use Jiminny\Exceptions\UnexpectedCallException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Close\Processor\AccountProcessor;
use Jiminny\Services\Crm\Close\Processor\MetadataProcessor;
use Jiminny\Services\Crm\Close\Processor\OpportunityProcessor;
use Jiminny\Services\Crm\Close\Processor\StageProcessor;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\Metadata\OpportunityMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Sentry;
use UnexpectedValueException;
class Service extends BaseService implements
CloseInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
SupportsObjectTypeParseInterface,
VerifyTaskExistsInterface
{
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private StandardFieldMetadata $standardFieldMetadata;
private MetadataProcessor $metadataProcessor;
private FieldValueConverter $fieldValueConverter;
private StageProcessor $stageProcessor;
private OpportunityProcessor $opportunityProcessor;
private AccountProcessor $accountProcessor;
public function __construct(
Client $client,
StandardFieldMetadata $standardFieldMetadata,
MetadataProcessor $metadataProcessor,
FieldValueConverter $fieldValueConverter,
StageProcessor $stageResolver,
OpportunityProcessor $opportunityProcessor,
AccountProcessor $accountProcessor,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
) {
parent::__construct();
$this->client = $client;
$this->standardFieldMetadata = $standardFieldMetadata;
$this->metadataProcessor = $metadataProcessor;
$this->fieldValueConverter = $fieldValueConverter;
$this->stageProcessor = $stageResolver;
$this->opportunityProcessor = $opportunityProcessor;
$this->accountProcessor = $accountProcessor;
}
public function getDisplayName(): string
{
return 'Close';
}
public function setConfiguration(Configuration $config): void
{
parent::setConfiguration($config);
$this->metadataProcessor->setConfiguration($config);
$this->stageProcessor->setConfiguration($config);
$this->opportunityProcessor->setConfiguration($config);
$this->accountProcessor->setConfiguration($config);
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
return $user->getTeam()->getOwner()->getSocialAccount(SocialAccount::PROVIDER_CLOSE);
}
private function getClient(): Client
{
if (! $this->client instanceof Client) {
throw new UnexpectedCallException('Client not set');
}
return $this->client;
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_OPPORTUNITY,
parent::OBJECT_CONTACT,
parent::OBJECT_ACCOUNT,
];
}
protected function getFields(string $crmObject): array
{
// not used
return [];
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Set up the activity field as the default Type.
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
/**
* @important Works only for custom fields
*/
public function syncField(Field $field): void
{
$resource = $this->convertObjectTypeToResource($field->getObjectType());
// We can only sync custom fields in this CRM.
if ($this->isCustomField($field->getCrmProviderId()) === false) {
return;
}
$crmField = $this->getClient()->fetchCustomFieldDefinition($resource, $field->getCrmProviderId());
$this->metadataProcessor->syncField($crmField);
}
private function isCustomField(string $fieldId): bool
{
return strpos($fieldId, 'cf_') === 0;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
// handled in syncFields()
return [];
}
/**
* @important We only support stages on the opportunity object
*
* @param string[]|null $types
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if (! $missingStageName) {
// This is taken care of by syncOrganization()
return null;
}
$stage = $this->stageProcessor->resolveFromStageId($missingStageName);
if ($stage instanceof Stage) {
return $stage;
}
$stageMetadata = $this->getClient()->fetchStage($missingStageName);
if (! $stageMetadata) {
$this->logger->error('Stage does not exist', [
'stage' => $missingStageName,
]);
return null;
}
return $this->stageProcessor->importStage($stageMetadata);
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
// Even though Close.io has the concept of "leads", they fit more into our concept of accounts.
return 0;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
// Not a supported entity.
return null;
}
/**
* @throws Exception
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
foreach ($this->getClient()->listAccounts($since) as $clAccount) {
// Only sync if previously imported.
if ($this->hasAccount($clAccount->getId())) {
$this->importAccount($clAccount);
$syncCount++;
}
}
} catch (Exception $exception) {
$this->logger->error('Account sync failed', [
'error' => $exception->getMessage(),
]);
throw $exception;
}
return $syncCount;
}
public function syncAccount(string $crmId): ?Account
{
return $this->accountProcessor->syncAccount($crmId);
}
private function importAccount($crmData): Account
{
return $this->accountProcessor->importAccountMetadata($crmData);
}
/**
* @throws CloseException
*/
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
$opportunities = [];
foreach ($strategies as $syncStrategy) {
$opportunitiesData = $syncStrategy->fetchOpportunities($parameters);
$opportunities[] = $opportunitiesData['data'];
if ($opportunitiesData['has_more']) {
$this->logger->info('[Close] Sync Opportunities - count warning', [
'team_id' => $this->config->getTeam()->getId(),
'total' => $opportunitiesData['total'],
'count' => $opportunitiesData['count'],
'skip' => $opportunitiesData['skip'],
'strategies_count' => count($strategies),
]);
}
}
$opportunities = array_merge(...$opportunities);
} catch (CrmException $exception) {
$this->logger->error('Fetching opportunity data failed', [
'team' => $this->getTeam()->getSlug(),
'error' => $exception->getMessage(),
]);
return 0;
}
foreach ($opportunities as $opportunityMetadata) {
try {
$this->importOpportunity($opportunityMetadata);
$syncCount++;
} catch (Exception $exception) {
$this->logger->warning('Opportunity sync failed', [
'opportunity' => $opportunityMetadata->getId(),
'error' => $exception->getMessage(),
]);
}
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = ['crm_id' => $crmId];
$opportunity = $strategy->fetchOpportunities($parameters);
if (empty($opportunity['data'])) {
return null;
}
return $this->importOpportunity($opportunity['data']);
}
private function importOpportunity(OpportunityMetadata $crmData): ?Opportunity
{
if (! $crmData->getLeadId()) {
$this->logger->warning('Opportunity does not have a lead ID', [
'opportunity' => $crmData->getId(),
]);
return null;
}
$account = $this->getConfiguration()
->accounts()
->where('crm_provider_id', $crmData->getLeadId())
->first();
if ($account === null) {
$account = $this->accountProcessor->syncAccount($crmData->getLeadId());
}
/** @var Profile $profile */
$profile = $this->getConfiguration()
->profiles()
->where('crm_provider_id', $crmData->getUserId())
->first();
$userId = $profile?->getUserId() ?? $account?->getUserId();
if ($userId === null) {
$this->logger->error('[Close] | Skip import, no user_id found', [
'id' => $crmData->getId(),
]);
return null;
}
$stage = $this->getConfiguration()
->stages()
->where('crm_provider_id', $crmData->getStageId())
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData->getStageId());
}
return $this->opportunityProcessor->import($crmData, $account, $stage, $profile);
}
/**
* @param array<string,string> $crmData
* @param string[] $crmFields
*/
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// handled in importOpportunity
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
/** No way to sync today.
$clContacts = $this->client->get('lead', [
'date_updated__gte' => $since->toDateString(),
'_order_by' => '-date_updated',
]);
foreach ($clContacts as $clContact) {
// Only sync if previously imported.
if ($this->hasContact($clContact['id'])) {
$this->importContact($clContact);
$syncCount++;
}
}
**/
} catch (Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
try {
$clContact = $this->client->get('contact/' . $crmId);
} catch (HttpNotFoundException $exception) {
return null;
}
return $this->importContact($clContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['lead_id']) {
$account = $this->team
->accounts()
->where('crm_provider_id', $crmData['lead_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['lead_id']);
}
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phones'] as $phoneNumber) {
if ($phoneNumber['type'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone(null, $phoneNumber['phone']);
} else {
$parsedNumber = $this->buildContactPhone(null, $phoneNumber['phone']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['updated_by'])->first();
$data = [
'account_id' => $account->id ?? null,
'team_id' => $this->team->id,
'user_id' => $profile?->user_id,
'owner_id' => $crmData['updated_by'],
'name' => $crmData['name'] ?? 'Unknown',
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => mb_strimwidth($crmData['title'] ?? '', 0, 128),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name'] ?? 'Unknown'
),
'remotely_created_at' => Carbon::parse($crmData['date_created']),
];
/** @var Contact */
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
public function syncOrganization(): void
{
$organisation = $this->getClient()->fetchOrganisation();
$this->metadataProcessor->syncOrganisation($organisation);
foreach ($organisation->getPipelines() as $pipelineMetadata) {
$this->metadataProcessor->syncPipeline($pipelineMetadata);
}
}
private function syncStandardFields(): void
{
// Currently we sync only opportunity fields
$stages = $this->getClient()->listStages();
foreach ($this->standardFieldMetadata->opportunity($stages) as $fieldMetadata) {
$this->metadataProcessor->syncField($fieldMetadata);
}
$this->config->save();
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$objectType = $this->convertObjectTypeToResource($fieldType);
$currentFields = $this->getClient()->listCustomFieldDefinitions($objectType);
foreach ($currentFields as $fieldMetadata) {
$this->metadataProcessor->syncField($fieldMetadata);
}
}
$this->config->save();
}
public function syncProfiles(?User $userToSearch = null): ?Profile
{
/*
* Fetch the profile of the user from the database
* Then fetch the user metadata from Close and update it
* In case there's no profile for the user, proceed with syncing all users
*/
$foundUser = null;
if ($userToSearch) {
$profile = $userToSearch->getProfile();
if ($profile instanceof Profile) {
$crmProviderId = $profile->getCrmProviderId();
if ($crmProviderId) {
$profileMetadata = $this->getClient()->fetchUser($crmProviderId);
if (! $profileMetadata instanceof ProfileMetadata) {
return null;
}
return $this->metadataProcessor->syncProfile($profileMetadata);
}
}
}
foreach ($this->getClient()->listUsers() as $userMetadata) {
$userProfile = $this->metadataProcessor->syncProfile($userMetadata);
if (
$userToSearch instanceof User
&& $userProfile instanceof Profile
&& $userProfile->getUserId() === $userToSearch->getId()
) {
$foundUser = $userProfile;
}
}
return $foundUser;
}
public function syncProfileFields(): void
{
// Not used.
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$data = Cache::remember($this->team->id . $name . $count . $offset, 300, function () use ($name, $count, $offset) {
$data = [];
try {
// If search phrase resembles phone number remove special symbols
if (preg_match('/^([0-9\s\-\+\(\)]*)$/', $name)) {
$name = '+' . preg_replace('/[\s\-\+\(\)]/', '', $name);
}
// Close do not provide a unified way to search, so we must hack our own.
$objects = $this->client->get('lead', [
'query' => 'sort:date_updated name:(' . $name . ') or email:(' . $name . ') or phone:(' . $name . ')',
'_limit' => $count, '_skip' => $offset,
]);
} catch (\GuzzleHttp\Exception\ServerException $exception) {
throw new ServiceUnavailableException($exception->getMessage());
}
foreach ($objects['data'] as $object) {
// We need a contact to dial it.
if (empty($object['contacts'])) {
continue;
}
foreach ($object['contacts'] as $contact) {
$record = [
'crmId' => $contact['id'],
'crmUrl' => $this->generateProviderUrl($object['id'], 'account'),
'name' => $contact['name'],
'industry' => null,
'title' => $contact['title'],
'organization' => $object['display_name'],
'prospectType' => 'contact',
'phoneNumbers' => [],
];
foreach ($contact['phones'] as $phone) {
if ($phone['type'] === 'mobile') {
$number = $this->buildContactMobilePhone(null, $phone['phone']);
$record['phoneNumbers'][] = [
'number' => $number,
'nationalFormat' => phone_national(null, $number),
'type' => 'mobile',
];
} else {
$parsedNumber = $this->buildContactPhone(null, $phone['phone']);
// Add phone number to record.
if (empty($parsedNumber['phone']) === false) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national(null, $parsedNumber['phone']),
'type' => 'phone',
];
}
}
}
$data[] = $record;
}
}
return $data;
});
return $data;
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'lead_id' => $account->crm_provider_id,
'_order_by' => '-date_updated',
];
$onlyOpen = true;
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['_order_by'] = '-date_updated';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['_order_by'] = '-date_created';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['_order_by'] = 'date_created';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['_order_by'] = '-date_updated';
$onlyOpen = false;
}
if ($onlyOpen) {
$params['status_type__in'] = 'active,won';
}
$clOpportunities = $this->client->get('opportunity', $params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($clOpportunities['data'] as $clOpportunity) {
$stage = $this->config
->stages()
->where('crm_provider_id', $clOpportunity['status_id'])
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $clOpportunity['status_id']);
}
$record = [
'crmId' => $clOpportunity['id'],
'name' => $clOpportunity['note'],
'value' => currency_format($clOpportunity['value'], $clOpportunity['value_currency']),
'won' => $stage->probability === 100.00,
'closed' => $clOpportunity['status_type'] !== 'active',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [],
];
if ($ownerId && isset($clOpportunity['user_id']) && $clOpportunity['user_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
$crmId = null;
if ($objectType === 'contact') {
$contact = $this->syncContact($objectId);
if ($contact && $contact->account_id) {
$crmId = $contact->account->crm_provider_id;
}
} else {
$crmId = $objectId;
}
if ($crmId) {
$clTasks = $this->client->get('task', [
'lead_id' => $crmId,
'_type' => 'lead',
'assigned_to' => $this->profile->crm_provider_id,
'is_complete' => 'false',
'_order_by' => 'date',
]);
foreach ($clTasks['data'] as $clTask) {
$data[] = [
'crmId' => $clTask['id'],
'subject' => $clTask['text'],
'due' => $clTask['date'] ?? null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(email(email:"' . $email . '"))',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
foreach ($clContact['emails'] as $clEmail) {
if ($email === $clEmail['email']) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : null;
}
}
}
}
return null;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
// Check if the user is internal.
$teamMember = $this->team->users()->where('phone', $phone)->exists();
// Skip the attendee if internal.
if ($teamMember === false) {
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(' . $phone . ')',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
foreach ($clContact['phones'] as $clPhone) {
if ($phone === $clPhone['phone']) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : null;
}
}
}
}
}
return null;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(name:"' . $name . '")',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
if ($clContact['name'] === $name || $clContact['display_name'] === $name) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : false;
}
}
}
return false;
});
return is_array($result) ? $result : null;
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
private function convertCrmData(string $crmId, ?int $userId = null): array
{
$lead = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
$contact = $this->syncContact($crmId);
if ($contact) {
$account = $contact->account;
if ($contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account) {
$countryCode = $account->country_code;
}
try {
$cpOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId,
);
if (! empty($cpOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception) {
// Nothing to see here.
}
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
public function saveActivity(Activity $activity): Activity
{
switch ($activity->type) {
case Activity::TYPE_CONFERENCE:
case Activity::TYPE_SOFTPHONE:
case Activity::TYPE_SOFTPHONE_INBOUND:
$activity = $this->buildCallPayload($activity);
break;
case Activity::TYPE_SMS_INBOUND:
case Activity::TYPE_SMS_OUTBOUND:
$activity = $this->buildTextMessagePayload($activity);
break;
}
return $activity;
}
private function mapStatus(string $status): string
{
switch ($status) {
case Activity::STATUS_COMPLETED:
case Activity::STATUS_IN_PROGRESS:
case Activity::STATUS_FAILED:
case Activity::STATUS_NO_ANSWER:
case Activity::STATUS_BUSY:
default:
return $status;
case Activity::STATUS_CANCELLED:
return 'cancel';
}
}
/**
* @throws CrmException
*/
private function buildCallPayload(Activity $activity): Activity
{
try {
if ($activity->crm_provider_id) {
// The activity should be logged under the existing Task (not Activity).
$data = [
'_type' => 'lead',
'lead_id' => $activity->account->crm_provider_id,
'assigned_to' => $this->profile->crm_provider_id,
'text' => $this->generateActivityDescription($activity),
'date' => $activity->getActualEndTime()->toDateString(),
'is_complete' => true,
];
$this->logger->info('[Close CRM] Updating task', [
'activity' => $activity->id,
'crm_id' => $activity->crm_provider_id,
'data' => $data,
]);
$this->client->put('task/' . $activity->crm_provider_id, $data);
} else {
// Just create an activity.
$data = [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'direction' => $activity->getCrmType() === Activity::TYPE_SOFTPHONE ? 'outbound' : 'inbound',
'status' => $this->mapStatus($activity->getStatus()),
'note' => $this->generateActivityDescription($activity),
'duration' => $this->mapStatus($activity->getStatus()) !== 'cancel' ? $activity->duration : 0,
'phone' => $activity->to ? $activity->to->phone_number : null,
];
$clActivity = $this->client->post('activity/call', $data);
$this->logger->info('[Close CRM] Creating activity', [
'activity' => $activity->id,
'crm_id' => $clActivity['id'],
'data' => $data,
'response' => $clActivity,
]);
$activity->crm_provider_id = $clActivity['id'];
$activity->save();
}
} catch (ClientException $exception) {
$response = $exception->getResponse();
if ($response === null) {
// Trying to debug weird cases where this is null.
Sentry::captureException($exception);
}
$responseBody = $response->getBody();
$message = $responseBody;
$errorCode = $response->getStatusCode();
$jsonResponse = json_decode($responseBody, true);
if (isset($jsonResponse[0]['message'])) {
$message = $jsonResponse[0]['message'];
}
throw new CrmException($message, $errorCode);
}
return $activity;
}
private function buildTextMessagePayload(Activity $activity): Activity
{
$clActivity = $this->client->post('activity/sms', [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'status' => $activity->getType() === Activity::TYPE_SMS_OUTBOUND ? 'sent' : 'inbox',
'text' => $this->generateActivityDescription($activity),
'remote_phone' => $activity->to ? $activity->to->phone_number : null,
'local_phone' => $activity->to ? $activity->to->phone_number : null,
'source' => 'Close.io',
]);
$activity->crm_provider_id = $clActivity['id'];
$activity->save();
return $activity;
}
private function generateActivityDescription(Activity $activity): string
{
$description = '';
switch ($activity->type) {
case Activity::TYPE_SOFTPHONE:
case Activity::TYPE_SOFTPHONE_INBOUND:
case Activity::TYPE_CONFERENCE:
if ($activity->hasActivityType()) {
$description = $activity->getActivityType()->getName() . PHP_EOL . PHP_EOL;
}
if ($activity->hasTitle()) {
$description .= $activity->getTitle() . PHP_EOL;
}
if ($activity->hasReasonCodeBotKicked()) {
$description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;
// When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.
} elseif ($activity->hasReasonCodeNotCompliant()) {
$description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;
} elseif ($activity->canReviewActivity()) {
$playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);
$description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;
}
if ($activity->type === Activity::TYPE_CONFERENCE) {
$description .= 'Attendees:'
. PHP_EOL
. (new FilterJoinedParticipants())->toString($activity);
}
if (\count($activity->notes) > 0) {
$description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;
foreach ($activity->notes as $note) {
$time = ($note->time > 3600) ? gmdate('H:i:s', $note->time) : gmdate('i:s', $note->time);
$description .= $time . ' ' . $note->note . PHP_EOL;
}
}
// Get all private messages.
$messages = $activity->messages()
->where('is_private', 1)
->orderBy('created_at', 'asc');
if ($messages->count() > 0) {
$description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;
foreach ($messages->get() as $message) {
$description .= $message->participant->name . ': ' . $message->message . PHP_EOL;
}
}
// Get all public messages.
$messages = $activity->messages()
->where('is_private', 0)
->orderBy('created_at', 'asc');
if ($messages->count() > 0) {
$description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;
foreach ($messages->get() as $message) {
$description .= $message->participant->name . ': ' . $message->message . PHP_EOL;
}
}
if ($activity->summary) {
$description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;
}
break;
case Activity::TYPE_SMS_INBOUND:
case Activity::TYPE_SMS_OUTBOUND:
$description = $activity->description;
break;
}
return $description;
}
public function saveFollowupActivity(Activity $activity, array $fields): ?string
{
// This is the user provided activity subject field.
if (empty($fields['name'])) {
return null;
}
$due = null;
if (empty($fields['due_date']) === false) {
$formatDue = Carbon::parse($fields['due_date']);
$due = $formatDue->toDateTimeString();
}
$clTask = $this->client->post('task', [
'_type' => 'lead',
'lead_id' => $activity->account->crm_provider_id,
'assigned_to' => $this->profile->crm_provider_id,
'text' => $fields['name'],
'date' => $due,
'is_complete' => false,
]);
// We don't actually create a corresponding activity object on our side yet.
return $clTask['id'];
}
/**
* Store transcripts as note.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
if ($activity->account_id === null) {
// We can only log to accounts (leads).
return;
}
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, self::NOTE_BODY_MAX_LENGTH);
$clActivity = $this->client->post('activity/note', [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'note' => $transcripts,
]);
// Store CRM Activity ID in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $clActivity['id'];
$transcription->save();
}
public function parseObjectType(string $objectId): string
{
if (Str::startsWith($objectId, 'lead')) {
return 'account';
}
if (Str::startsWith($objectId, 'cont')) {
return 'contact';
}
if (Str::startsWith($objectId, 'oppo')) {
return 'opportunity';
}
throw new InvalidArgumentException('Unsupported Object Type');
}
/**
* @inheritdoc
*/
public function updateStage($crmObject, Stage $stage): void
{
if ($crmObject instanceof Lead) {
// This would never get invoked since we merge lead/accounts in Close.
$this->client->put('lead/' . $crmObject->crm_provider_id, [
'status' => $stage->crm_provider_id,
]);
} else {
$this->client->put('opportunity/' . $crmObject->crm_provider_id, [
'status_id' => $stage->crm_provider_id,
]);
}
}
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$this->getClient()->updateObject($this->convertObjectTypeToResource($objectType), $objectId, $data);
}
public function prepareValueForUpdate(array $params): array
{
$convertedValue = $this->fieldValueConverter->convertToCrm(
$this->config,
$params['fieldName'],
$params['fieldValue'],
);
if ($this->isCustomField($params['fieldName'])) {
$params['fieldName'] = 'custom.' . $params['fieldName'];
}
$params['fieldValue'] = $convertedValue;
return parent::prepareValueForUpdate($params);
}
public function getRecord(string $objectType, string $objectId, array $fields = []): array
{
return $this->client->get($this->convertObjectTypeToResource($objectType) . '/' . $objectId);
}
/**
*
* @throws UnexpectedValueException
*/
private function convertObjectTypeToResource(string $objectType): string
{
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
return 'opportunity';
case FieldData::OBJECT_CONTACT:
return 'contact';
case FieldData::OBJECT_ACCOUNT:
return 'lead';
case FieldData::OBJECT_TASK:
return 'activity';
default:
throw new UnexpectedValueException('Unsupported object type "' . $objectType . '"');
}
}
public function generateProviderUrl(string $providerId, string $objectType): ?string
{
$baseUrl = 'https://app.close.com/';
$url = null;
switch ($objectType) {
case 'account':
$url = $baseUrl . 'lead/' . $providerId;
break;
case 'contact':
$contact = $this->config->contacts()->where('crm_provider_id', $providerId)->first();
if ($contact && $contact->account_id) {
$url = $baseUrl . 'lead/' . $contact->account->crm_provider_id;
}
break;
default:
// Sadly we can't deeplink to anything else in Close UI.
$url = null;
}
return $url;
}
/**
* Generate transcription for the activity.
*/
private function generateTranscription(Activity $activity): string
{
if (! $this->config->store_transcript) {
// If sending transcription to activity toggle is disabled
return '';
}
return $this->transcriptionService
->findTranscriptionByActivity($activity)
->map(static function (array $transcriptionSegment): string {
return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];
})
->implode(PHP_EOL);
}
public function verifyTaskExists(Activity $activity): bool
{
$crmProviderId = $activity->getCrmProviderId();
$cacheKey = "crm_task_exists:{$this->config->getId()}:$crmProviderId";
return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {
try {
$client = $this->getClient();
$task = $client->get('task/' . $crmProviderId);
return ! empty($task);
} catch (HttpNotFoundException) {
// Task not found in CRM - this is expected and permanent
$this->logger->info('[Close] Task not found during verification', [
'task_id' => $crmProviderId,
'config_id' => $this->config->getId(),
]);
...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"8","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"39","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"5","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Close;\n\nuse Cache;\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CloseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\ServiceUnavailableException;\nuse Jiminny\\Exceptions\\UnexpectedCallException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\AccountProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\MetadataProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\OpportunityProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\StageProcessor;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\Metadata\\OpportunityMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Sentry;\nuse UnexpectedValueException;\n\nclass Service extends BaseService implements\n CloseInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n SupportsObjectTypeParseInterface,\n VerifyTaskExistsInterface\n{\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private StandardFieldMetadata $standardFieldMetadata;\n private MetadataProcessor $metadataProcessor;\n private FieldValueConverter $fieldValueConverter;\n private StageProcessor $stageProcessor;\n private OpportunityProcessor $opportunityProcessor;\n private AccountProcessor $accountProcessor;\n\n public function __construct(\n Client $client,\n StandardFieldMetadata $standardFieldMetadata,\n MetadataProcessor $metadataProcessor,\n FieldValueConverter $fieldValueConverter,\n StageProcessor $stageResolver,\n OpportunityProcessor $opportunityProcessor,\n AccountProcessor $accountProcessor,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->standardFieldMetadata = $standardFieldMetadata;\n $this->metadataProcessor = $metadataProcessor;\n $this->fieldValueConverter = $fieldValueConverter;\n $this->stageProcessor = $stageResolver;\n $this->opportunityProcessor = $opportunityProcessor;\n $this->accountProcessor = $accountProcessor;\n }\n\n public function getDisplayName(): string\n {\n return 'Close';\n }\n\n public function setConfiguration(Configuration $config): void\n {\n parent::setConfiguration($config);\n\n $this->metadataProcessor->setConfiguration($config);\n $this->stageProcessor->setConfiguration($config);\n $this->opportunityProcessor->setConfiguration($config);\n $this->accountProcessor->setConfiguration($config);\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n return $user->getTeam()->getOwner()->getSocialAccount(SocialAccount::PROVIDER_CLOSE);\n }\n\n private function getClient(): Client\n {\n if (! $this->client instanceof Client) {\n throw new UnexpectedCallException('Client not set');\n }\n\n return $this->client;\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_OPPORTUNITY,\n parent::OBJECT_CONTACT,\n parent::OBJECT_ACCOUNT,\n ];\n }\n\n protected function getFields(string $crmObject): array\n {\n // not used\n return [];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Set up the activity field as the default Type.\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n /**\n * @important Works only for custom fields\n */\n public function syncField(Field $field): void\n {\n $resource = $this->convertObjectTypeToResource($field->getObjectType());\n\n // We can only sync custom fields in this CRM.\n if ($this->isCustomField($field->getCrmProviderId()) === false) {\n return;\n }\n\n $crmField = $this->getClient()->fetchCustomFieldDefinition($resource, $field->getCrmProviderId());\n\n $this->metadataProcessor->syncField($crmField);\n }\n\n private function isCustomField(string $fieldId): bool\n {\n return strpos($fieldId, 'cf_') === 0;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n // handled in syncFields()\n return [];\n }\n\n /**\n * @important We only support stages on the opportunity object\n *\n * @param string[]|null $types\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if (! $missingStageName) {\n // This is taken care of by syncOrganization()\n return null;\n }\n\n $stage = $this->stageProcessor->resolveFromStageId($missingStageName);\n\n if ($stage instanceof Stage) {\n return $stage;\n }\n\n $stageMetadata = $this->getClient()->fetchStage($missingStageName);\n\n if (! $stageMetadata) {\n $this->logger->error('Stage does not exist', [\n 'stage' => $missingStageName,\n ]);\n\n return null;\n }\n\n\n return $this->stageProcessor->importStage($stageMetadata);\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n // Even though Close.io has the concept of \"leads\", they fit more into our concept of accounts.\n return 0;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n // Not a supported entity.\n return null;\n }\n\n /**\n * @throws Exception\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n foreach ($this->getClient()->listAccounts($since) as $clAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($clAccount->getId())) {\n $this->importAccount($clAccount);\n $syncCount++;\n }\n }\n } catch (Exception $exception) {\n $this->logger->error('Account sync failed', [\n 'error' => $exception->getMessage(),\n ]);\n\n throw $exception;\n }\n\n return $syncCount;\n }\n\n public function syncAccount(string $crmId): ?Account\n {\n return $this->accountProcessor->syncAccount($crmId);\n }\n\n private function importAccount($crmData): Account\n {\n return $this->accountProcessor->importAccountMetadata($crmData);\n }\n\n /**\n * @throws CloseException\n */\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n $opportunities = [];\n foreach ($strategies as $syncStrategy) {\n $opportunitiesData = $syncStrategy->fetchOpportunities($parameters);\n $opportunities[] = $opportunitiesData['data'];\n\n if ($opportunitiesData['has_more']) {\n $this->logger->info('[Close] Sync Opportunities - count warning', [\n 'team_id' => $this->config->getTeam()->getId(),\n 'total' => $opportunitiesData['total'],\n 'count' => $opportunitiesData['count'],\n 'skip' => $opportunitiesData['skip'],\n 'strategies_count' => count($strategies),\n ]);\n }\n }\n\n $opportunities = array_merge(...$opportunities);\n } catch (CrmException $exception) {\n $this->logger->error('Fetching opportunity data failed', [\n 'team' => $this->getTeam()->getSlug(),\n 'error' => $exception->getMessage(),\n ]);\n\n return 0;\n }\n\n foreach ($opportunities as $opportunityMetadata) {\n try {\n $this->importOpportunity($opportunityMetadata);\n $syncCount++;\n } catch (Exception $exception) {\n $this->logger->warning('Opportunity sync failed', [\n 'opportunity' => $opportunityMetadata->getId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = ['crm_id' => $crmId];\n\n $opportunity = $strategy->fetchOpportunities($parameters);\n\n if (empty($opportunity['data'])) {\n return null;\n }\n\n return $this->importOpportunity($opportunity['data']);\n }\n\n private function importOpportunity(OpportunityMetadata $crmData): ?Opportunity\n {\n if (! $crmData->getLeadId()) {\n $this->logger->warning('Opportunity does not have a lead ID', [\n 'opportunity' => $crmData->getId(),\n ]);\n\n return null;\n }\n\n $account = $this->getConfiguration()\n ->accounts()\n ->where('crm_provider_id', $crmData->getLeadId())\n ->first();\n\n if ($account === null) {\n $account = $this->accountProcessor->syncAccount($crmData->getLeadId());\n }\n\n /** @var Profile $profile */\n $profile = $this->getConfiguration()\n ->profiles()\n ->where('crm_provider_id', $crmData->getUserId())\n ->first();\n\n $userId = $profile?->getUserId() ?? $account?->getUserId();\n if ($userId === null) {\n $this->logger->error('[Close] | Skip import, no user_id found', [\n 'id' => $crmData->getId(),\n ]);\n\n return null;\n }\n\n $stage = $this->getConfiguration()\n ->stages()\n ->where('crm_provider_id', $crmData->getStageId())\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData->getStageId());\n }\n\n return $this->opportunityProcessor->import($crmData, $account, $stage, $profile);\n }\n\n /**\n * @param array<string,string> $crmData\n * @param string[] $crmFields\n */\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // handled in importOpportunity\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n /** No way to sync today.\n $clContacts = $this->client->get('lead', [\n 'date_updated__gte' => $since->toDateString(),\n '_order_by' => '-date_updated',\n ]);\n\n foreach ($clContacts as $clContact) {\n // Only sync if previously imported.\n if ($this->hasContact($clContact['id'])) {\n $this->importContact($clContact);\n $syncCount++;\n }\n }\n **/\n } catch (Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n try {\n $clContact = $this->client->get('contact/' . $crmId);\n } catch (HttpNotFoundException $exception) {\n return null;\n }\n\n return $this->importContact($clContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['lead_id']) {\n $account = $this->team\n ->accounts()\n ->where('crm_provider_id', $crmData['lead_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['lead_id']);\n }\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phones'] as $phoneNumber) {\n if ($phoneNumber['type'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone(null, $phoneNumber['phone']);\n } else {\n $parsedNumber = $this->buildContactPhone(null, $phoneNumber['phone']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['updated_by'])->first();\n\n $data = [\n 'account_id' => $account->id ?? null,\n 'team_id' => $this->team->id,\n 'user_id' => $profile?->user_id,\n 'owner_id' => $crmData['updated_by'],\n 'name' => $crmData['name'] ?? 'Unknown',\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => mb_strimwidth($crmData['title'] ?? '', 0, 128),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name'] ?? 'Unknown'\n ),\n 'remotely_created_at' => Carbon::parse($crmData['date_created']),\n ];\n\n /** @var Contact */\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n public function syncOrganization(): void\n {\n $organisation = $this->getClient()->fetchOrganisation();\n\n $this->metadataProcessor->syncOrganisation($organisation);\n\n foreach ($organisation->getPipelines() as $pipelineMetadata) {\n $this->metadataProcessor->syncPipeline($pipelineMetadata);\n }\n }\n\n private function syncStandardFields(): void\n {\n // Currently we sync only opportunity fields\n $stages = $this->getClient()->listStages();\n foreach ($this->standardFieldMetadata->opportunity($stages) as $fieldMetadata) {\n $this->metadataProcessor->syncField($fieldMetadata);\n }\n\n $this->config->save();\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $objectType = $this->convertObjectTypeToResource($fieldType);\n $currentFields = $this->getClient()->listCustomFieldDefinitions($objectType);\n\n foreach ($currentFields as $fieldMetadata) {\n $this->metadataProcessor->syncField($fieldMetadata);\n }\n }\n\n $this->config->save();\n }\n\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n /*\n * Fetch the profile of the user from the database\n * Then fetch the user metadata from Close and update it\n * In case there's no profile for the user, proceed with syncing all users\n */\n $foundUser = null;\n\n if ($userToSearch) {\n $profile = $userToSearch->getProfile();\n\n if ($profile instanceof Profile) {\n $crmProviderId = $profile->getCrmProviderId();\n\n if ($crmProviderId) {\n $profileMetadata = $this->getClient()->fetchUser($crmProviderId);\n\n if (! $profileMetadata instanceof ProfileMetadata) {\n return null;\n }\n\n return $this->metadataProcessor->syncProfile($profileMetadata);\n }\n }\n }\n\n foreach ($this->getClient()->listUsers() as $userMetadata) {\n $userProfile = $this->metadataProcessor->syncProfile($userMetadata);\n\n if (\n $userToSearch instanceof User\n && $userProfile instanceof Profile\n && $userProfile->getUserId() === $userToSearch->getId()\n ) {\n $foundUser = $userProfile;\n }\n }\n\n return $foundUser;\n }\n\n public function syncProfileFields(): void\n {\n // Not used.\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $data = Cache::remember($this->team->id . $name . $count . $offset, 300, function () use ($name, $count, $offset) {\n $data = [];\n\n try {\n // If search phrase resembles phone number remove special symbols\n if (preg_match('/^([0-9\\s\\-\\+\\(\\)]*)$/', $name)) {\n $name = '+' . preg_replace('/[\\s\\-\\+\\(\\)]/', '', $name);\n }\n\n // Close do not provide a unified way to search, so we must hack our own.\n $objects = $this->client->get('lead', [\n 'query' => 'sort:date_updated name:(' . $name . ') or email:(' . $name . ') or phone:(' . $name . ')',\n '_limit' => $count, '_skip' => $offset,\n ]);\n } catch (\\GuzzleHttp\\Exception\\ServerException $exception) {\n throw new ServiceUnavailableException($exception->getMessage());\n }\n\n foreach ($objects['data'] as $object) {\n // We need a contact to dial it.\n if (empty($object['contacts'])) {\n continue;\n }\n\n foreach ($object['contacts'] as $contact) {\n $record = [\n 'crmId' => $contact['id'],\n 'crmUrl' => $this->generateProviderUrl($object['id'], 'account'),\n 'name' => $contact['name'],\n 'industry' => null,\n 'title' => $contact['title'],\n 'organization' => $object['display_name'],\n 'prospectType' => 'contact',\n 'phoneNumbers' => [],\n ];\n\n foreach ($contact['phones'] as $phone) {\n if ($phone['type'] === 'mobile') {\n $number = $this->buildContactMobilePhone(null, $phone['phone']);\n\n $record['phoneNumbers'][] = [\n 'number' => $number,\n 'nationalFormat' => phone_national(null, $number),\n 'type' => 'mobile',\n ];\n } else {\n $parsedNumber = $this->buildContactPhone(null, $phone['phone']);\n\n // Add phone number to record.\n if (empty($parsedNumber['phone']) === false) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national(null, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n }\n }\n\n $data[] = $record;\n }\n }\n\n return $data;\n });\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'lead_id' => $account->crm_provider_id,\n '_order_by' => '-date_updated',\n ];\n\n $onlyOpen = true;\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['_order_by'] = '-date_updated';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['_order_by'] = '-date_created';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['_order_by'] = 'date_created';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['_order_by'] = '-date_updated';\n $onlyOpen = false;\n }\n\n if ($onlyOpen) {\n $params['status_type__in'] = 'active,won';\n }\n\n $clOpportunities = $this->client->get('opportunity', $params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($clOpportunities['data'] as $clOpportunity) {\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', $clOpportunity['status_id'])\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $clOpportunity['status_id']);\n }\n\n $record = [\n 'crmId' => $clOpportunity['id'],\n 'name' => $clOpportunity['note'],\n 'value' => currency_format($clOpportunity['value'], $clOpportunity['value_currency']),\n 'won' => $stage->probability === 100.00,\n 'closed' => $clOpportunity['status_type'] !== 'active',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [],\n ];\n\n if ($ownerId && isset($clOpportunity['user_id']) && $clOpportunity['user_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n $crmId = null;\n\n if ($objectType === 'contact') {\n $contact = $this->syncContact($objectId);\n\n if ($contact && $contact->account_id) {\n $crmId = $contact->account->crm_provider_id;\n }\n } else {\n $crmId = $objectId;\n }\n\n if ($crmId) {\n $clTasks = $this->client->get('task', [\n 'lead_id' => $crmId,\n '_type' => 'lead',\n 'assigned_to' => $this->profile->crm_provider_id,\n 'is_complete' => 'false',\n '_order_by' => 'date',\n ]);\n\n foreach ($clTasks['data'] as $clTask) {\n $data[] = [\n 'crmId' => $clTask['id'],\n 'subject' => $clTask['text'],\n 'due' => $clTask['date'] ?? null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(email(email:\"' . $email . '\"))',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n foreach ($clContact['emails'] as $clEmail) {\n if ($email === $clEmail['email']) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(' . $phone . ')',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n foreach ($clContact['phones'] as $clPhone) {\n if ($phone === $clPhone['phone']) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(name:\"' . $name . '\")',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n if ($clContact['name'] === $name || $clContact['display_name'] === $name) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n }\n }\n }\n\n return false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n private function convertCrmData(string $crmId, ?int $userId = null): array\n {\n $lead = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n $contact = $this->syncContact($crmId);\n if ($contact) {\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function mapStatus(string $status): string\n {\n switch ($status) {\n case Activity::STATUS_COMPLETED:\n case Activity::STATUS_IN_PROGRESS:\n case Activity::STATUS_FAILED:\n case Activity::STATUS_NO_ANSWER:\n case Activity::STATUS_BUSY:\n default:\n return $status;\n case Activity::STATUS_CANCELLED:\n return 'cancel';\n }\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $data = [\n '_type' => 'lead',\n 'lead_id' => $activity->account->crm_provider_id,\n 'assigned_to' => $this->profile->crm_provider_id,\n 'text' => $this->generateActivityDescription($activity),\n 'date' => $activity->getActualEndTime()->toDateString(),\n 'is_complete' => true,\n ];\n\n $this->logger->info('[Close CRM] Updating task', [\n 'activity' => $activity->id,\n 'crm_id' => $activity->crm_provider_id,\n 'data' => $data,\n ]);\n\n $this->client->put('task/' . $activity->crm_provider_id, $data);\n } else {\n // Just create an activity.\n $data = [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'direction' => $activity->getCrmType() === Activity::TYPE_SOFTPHONE ? 'outbound' : 'inbound',\n 'status' => $this->mapStatus($activity->getStatus()),\n 'note' => $this->generateActivityDescription($activity),\n 'duration' => $this->mapStatus($activity->getStatus()) !== 'cancel' ? $activity->duration : 0,\n 'phone' => $activity->to ? $activity->to->phone_number : null,\n ];\n\n $clActivity = $this->client->post('activity/call', $data);\n\n $this->logger->info('[Close CRM] Creating activity', [\n 'activity' => $activity->id,\n 'crm_id' => $clActivity['id'],\n 'data' => $data,\n 'response' => $clActivity,\n ]);\n\n $activity->crm_provider_id = $clActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n $response = $exception->getResponse();\n\n if ($response === null) {\n // Trying to debug weird cases where this is null.\n Sentry::captureException($exception);\n }\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n $clActivity = $this->client->post('activity/sms', [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'status' => $activity->getType() === Activity::TYPE_SMS_OUTBOUND ? 'sent' : 'inbox',\n 'text' => $this->generateActivityDescription($activity),\n 'remote_phone' => $activity->to ? $activity->to->phone_number : null,\n 'local_phone' => $activity->to ? $activity->to->phone_number : null,\n 'source' => 'Close.io',\n ]);\n\n $activity->crm_provider_id = $clActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n if ($activity->hasActivityType()) {\n $description = $activity->getActivityType()->getName() . PHP_EOL . PHP_EOL;\n }\n if ($activity->hasTitle()) {\n $description .= $activity->getTitle() . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->type === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $time = ($note->time > 3600) ? gmdate('H:i:s', $note->time) : gmdate('i:s', $note->time);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['name'])) {\n return null;\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::parse($fields['due_date']);\n $due = $formatDue->toDateTimeString();\n }\n\n $clTask = $this->client->post('task', [\n '_type' => 'lead',\n 'lead_id' => $activity->account->crm_provider_id,\n 'assigned_to' => $this->profile->crm_provider_id,\n 'text' => $fields['name'],\n 'date' => $due,\n 'is_complete' => false,\n ]);\n\n // We don't actually create a corresponding activity object on our side yet.\n return $clTask['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n if ($activity->account_id === null) {\n // We can only log to accounts (leads).\n return;\n }\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, self::NOTE_BODY_MAX_LENGTH);\n\n $clActivity = $this->client->post('activity/note', [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'note' => $transcripts,\n ]);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $clActivity['id'];\n $transcription->save();\n }\n\n public function parseObjectType(string $objectId): string\n {\n if (Str::startsWith($objectId, 'lead')) {\n return 'account';\n }\n\n if (Str::startsWith($objectId, 'cont')) {\n return 'contact';\n }\n\n if (Str::startsWith($objectId, 'oppo')) {\n return 'opportunity';\n }\n\n throw new InvalidArgumentException('Unsupported Object Type');\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n // This would never get invoked since we merge lead/accounts in Close.\n $this->client->put('lead/' . $crmObject->crm_provider_id, [\n 'status' => $stage->crm_provider_id,\n ]);\n } else {\n $this->client->put('opportunity/' . $crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $this->getClient()->updateObject($this->convertObjectTypeToResource($objectType), $objectId, $data);\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $convertedValue = $this->fieldValueConverter->convertToCrm(\n $this->config,\n $params['fieldName'],\n $params['fieldValue'],\n );\n\n if ($this->isCustomField($params['fieldName'])) {\n $params['fieldName'] = 'custom.' . $params['fieldName'];\n }\n\n $params['fieldValue'] = $convertedValue;\n\n return parent::prepareValueForUpdate($params);\n }\n\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->client->get($this->convertObjectTypeToResource($objectType) . '/' . $objectId);\n }\n\n /**\n *\n * @throws UnexpectedValueException\n */\n private function convertObjectTypeToResource(string $objectType): string\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return 'opportunity';\n\n case FieldData::OBJECT_CONTACT:\n return 'contact';\n\n case FieldData::OBJECT_ACCOUNT:\n return 'lead';\n\n case FieldData::OBJECT_TASK:\n return 'activity';\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.close.com/';\n $url = null;\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'lead/' . $providerId;\n\n break;\n\n case 'contact':\n $contact = $this->config->contacts()->where('crm_provider_id', $providerId)->first();\n if ($contact && $contact->account_id) {\n $url = $baseUrl . 'lead/' . $contact->account->crm_provider_id;\n }\n\n break;\n\n default:\n // Sadly we can't deeplink to anything else in Close UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $client = $this->getClient();\n $task = $client->get('task/' . $crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Close] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (CloseException $e) {\n // Handle 404 responses from Close API\n if ($e->getResponseStatusCode() === 404) {\n $this->logger->info('[Close] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Close exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Close;\n\nuse Cache;\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Str;\nuse InvalidArgumentException;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CloseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\ServiceUnavailableException;\nuse Jiminny\\Exceptions\\UnexpectedCallException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\AccountProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\MetadataProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\OpportunityProcessor;\nuse Jiminny\\Services\\Crm\\Close\\Processor\\StageProcessor;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\Metadata\\OpportunityMetadata;\nuse Jiminny\\Services\\Crm\\Metadata\\ProfileMetadata;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Sentry;\nuse UnexpectedValueException;\n\nclass Service extends BaseService implements\n CloseInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n SupportsObjectTypeParseInterface,\n VerifyTaskExistsInterface\n{\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private StandardFieldMetadata $standardFieldMetadata;\n private MetadataProcessor $metadataProcessor;\n private FieldValueConverter $fieldValueConverter;\n private StageProcessor $stageProcessor;\n private OpportunityProcessor $opportunityProcessor;\n private AccountProcessor $accountProcessor;\n\n public function __construct(\n Client $client,\n StandardFieldMetadata $standardFieldMetadata,\n MetadataProcessor $metadataProcessor,\n FieldValueConverter $fieldValueConverter,\n StageProcessor $stageResolver,\n OpportunityProcessor $opportunityProcessor,\n AccountProcessor $accountProcessor,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n ) {\n parent::__construct();\n\n $this->client = $client;\n $this->standardFieldMetadata = $standardFieldMetadata;\n $this->metadataProcessor = $metadataProcessor;\n $this->fieldValueConverter = $fieldValueConverter;\n $this->stageProcessor = $stageResolver;\n $this->opportunityProcessor = $opportunityProcessor;\n $this->accountProcessor = $accountProcessor;\n }\n\n public function getDisplayName(): string\n {\n return 'Close';\n }\n\n public function setConfiguration(Configuration $config): void\n {\n parent::setConfiguration($config);\n\n $this->metadataProcessor->setConfiguration($config);\n $this->stageProcessor->setConfiguration($config);\n $this->opportunityProcessor->setConfiguration($config);\n $this->accountProcessor->setConfiguration($config);\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n return $user->getTeam()->getOwner()->getSocialAccount(SocialAccount::PROVIDER_CLOSE);\n }\n\n private function getClient(): Client\n {\n if (! $this->client instanceof Client) {\n throw new UnexpectedCallException('Client not set');\n }\n\n return $this->client;\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_OPPORTUNITY,\n parent::OBJECT_CONTACT,\n parent::OBJECT_ACCOUNT,\n ];\n }\n\n protected function getFields(string $crmObject): array\n {\n // not used\n return [];\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Set up the activity field as the default Type.\n /** @var Field $activityField */\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n\n $fieldData = FieldDefinitions::followupFieldsFilter();\n\n foreach ($fieldData as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n /**\n * @important Works only for custom fields\n */\n public function syncField(Field $field): void\n {\n $resource = $this->convertObjectTypeToResource($field->getObjectType());\n\n // We can only sync custom fields in this CRM.\n if ($this->isCustomField($field->getCrmProviderId()) === false) {\n return;\n }\n\n $crmField = $this->getClient()->fetchCustomFieldDefinition($resource, $field->getCrmProviderId());\n\n $this->metadataProcessor->syncField($crmField);\n }\n\n private function isCustomField(string $fieldId): bool\n {\n return strpos($fieldId, 'cf_') === 0;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n // handled in syncFields()\n return [];\n }\n\n /**\n * @important We only support stages on the opportunity object\n *\n * @param string[]|null $types\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if (! $missingStageName) {\n // This is taken care of by syncOrganization()\n return null;\n }\n\n $stage = $this->stageProcessor->resolveFromStageId($missingStageName);\n\n if ($stage instanceof Stage) {\n return $stage;\n }\n\n $stageMetadata = $this->getClient()->fetchStage($missingStageName);\n\n if (! $stageMetadata) {\n $this->logger->error('Stage does not exist', [\n 'stage' => $missingStageName,\n ]);\n\n return null;\n }\n\n\n return $this->stageProcessor->importStage($stageMetadata);\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n // Even though Close.io has the concept of \"leads\", they fit more into our concept of accounts.\n return 0;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n // Not a supported entity.\n return null;\n }\n\n /**\n * @throws Exception\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n foreach ($this->getClient()->listAccounts($since) as $clAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($clAccount->getId())) {\n $this->importAccount($clAccount);\n $syncCount++;\n }\n }\n } catch (Exception $exception) {\n $this->logger->error('Account sync failed', [\n 'error' => $exception->getMessage(),\n ]);\n\n throw $exception;\n }\n\n return $syncCount;\n }\n\n public function syncAccount(string $crmId): ?Account\n {\n return $this->accountProcessor->syncAccount($crmId);\n }\n\n private function importAccount($crmData): Account\n {\n return $this->accountProcessor->importAccountMetadata($crmData);\n }\n\n /**\n * @throws CloseException\n */\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n $opportunities = [];\n foreach ($strategies as $syncStrategy) {\n $opportunitiesData = $syncStrategy->fetchOpportunities($parameters);\n $opportunities[] = $opportunitiesData['data'];\n\n if ($opportunitiesData['has_more']) {\n $this->logger->info('[Close] Sync Opportunities - count warning', [\n 'team_id' => $this->config->getTeam()->getId(),\n 'total' => $opportunitiesData['total'],\n 'count' => $opportunitiesData['count'],\n 'skip' => $opportunitiesData['skip'],\n 'strategies_count' => count($strategies),\n ]);\n }\n }\n\n $opportunities = array_merge(...$opportunities);\n } catch (CrmException $exception) {\n $this->logger->error('Fetching opportunity data failed', [\n 'team' => $this->getTeam()->getSlug(),\n 'error' => $exception->getMessage(),\n ]);\n\n return 0;\n }\n\n foreach ($opportunities as $opportunityMetadata) {\n try {\n $this->importOpportunity($opportunityMetadata);\n $syncCount++;\n } catch (Exception $exception) {\n $this->logger->warning('Opportunity sync failed', [\n 'opportunity' => $opportunityMetadata->getId(),\n 'error' => $exception->getMessage(),\n ]);\n }\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->client,\n ]);\n\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = ['crm_id' => $crmId];\n\n $opportunity = $strategy->fetchOpportunities($parameters);\n\n if (empty($opportunity['data'])) {\n return null;\n }\n\n return $this->importOpportunity($opportunity['data']);\n }\n\n private function importOpportunity(OpportunityMetadata $crmData): ?Opportunity\n {\n if (! $crmData->getLeadId()) {\n $this->logger->warning('Opportunity does not have a lead ID', [\n 'opportunity' => $crmData->getId(),\n ]);\n\n return null;\n }\n\n $account = $this->getConfiguration()\n ->accounts()\n ->where('crm_provider_id', $crmData->getLeadId())\n ->first();\n\n if ($account === null) {\n $account = $this->accountProcessor->syncAccount($crmData->getLeadId());\n }\n\n /** @var Profile $profile */\n $profile = $this->getConfiguration()\n ->profiles()\n ->where('crm_provider_id', $crmData->getUserId())\n ->first();\n\n $userId = $profile?->getUserId() ?? $account?->getUserId();\n if ($userId === null) {\n $this->logger->error('[Close] | Skip import, no user_id found', [\n 'id' => $crmData->getId(),\n ]);\n\n return null;\n }\n\n $stage = $this->getConfiguration()\n ->stages()\n ->where('crm_provider_id', $crmData->getStageId())\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData->getStageId());\n }\n\n return $this->opportunityProcessor->import($crmData, $account, $stage, $profile);\n }\n\n /**\n * @param array<string,string> $crmData\n * @param string[] $crmFields\n */\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // handled in importOpportunity\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n /** No way to sync today.\n $clContacts = $this->client->get('lead', [\n 'date_updated__gte' => $since->toDateString(),\n '_order_by' => '-date_updated',\n ]);\n\n foreach ($clContacts as $clContact) {\n // Only sync if previously imported.\n if ($this->hasContact($clContact['id'])) {\n $this->importContact($clContact);\n $syncCount++;\n }\n }\n **/\n } catch (Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n try {\n $clContact = $this->client->get('contact/' . $crmId);\n } catch (HttpNotFoundException $exception) {\n return null;\n }\n\n return $this->importContact($clContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['lead_id']) {\n $account = $this->team\n ->accounts()\n ->where('crm_provider_id', $crmData['lead_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['lead_id']);\n }\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phones'] as $phoneNumber) {\n if ($phoneNumber['type'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone(null, $phoneNumber['phone']);\n } else {\n $parsedNumber = $this->buildContactPhone(null, $phoneNumber['phone']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['updated_by'])->first();\n\n $data = [\n 'account_id' => $account->id ?? null,\n 'team_id' => $this->team->id,\n 'user_id' => $profile?->user_id,\n 'owner_id' => $crmData['updated_by'],\n 'name' => $crmData['name'] ?? 'Unknown',\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => mb_strimwidth($crmData['title'] ?? '', 0, 128),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name'] ?? 'Unknown'\n ),\n 'remotely_created_at' => Carbon::parse($crmData['date_created']),\n ];\n\n /** @var Contact */\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n public function syncOrganization(): void\n {\n $organisation = $this->getClient()->fetchOrganisation();\n\n $this->metadataProcessor->syncOrganisation($organisation);\n\n foreach ($organisation->getPipelines() as $pipelineMetadata) {\n $this->metadataProcessor->syncPipeline($pipelineMetadata);\n }\n }\n\n private function syncStandardFields(): void\n {\n // Currently we sync only opportunity fields\n $stages = $this->getClient()->listStages();\n foreach ($this->standardFieldMetadata->opportunity($stages) as $fieldMetadata) {\n $this->metadataProcessor->syncField($fieldMetadata);\n }\n\n $this->config->save();\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $objectType = $this->convertObjectTypeToResource($fieldType);\n $currentFields = $this->getClient()->listCustomFieldDefinitions($objectType);\n\n foreach ($currentFields as $fieldMetadata) {\n $this->metadataProcessor->syncField($fieldMetadata);\n }\n }\n\n $this->config->save();\n }\n\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n /*\n * Fetch the profile of the user from the database\n * Then fetch the user metadata from Close and update it\n * In case there's no profile for the user, proceed with syncing all users\n */\n $foundUser = null;\n\n if ($userToSearch) {\n $profile = $userToSearch->getProfile();\n\n if ($profile instanceof Profile) {\n $crmProviderId = $profile->getCrmProviderId();\n\n if ($crmProviderId) {\n $profileMetadata = $this->getClient()->fetchUser($crmProviderId);\n\n if (! $profileMetadata instanceof ProfileMetadata) {\n return null;\n }\n\n return $this->metadataProcessor->syncProfile($profileMetadata);\n }\n }\n }\n\n foreach ($this->getClient()->listUsers() as $userMetadata) {\n $userProfile = $this->metadataProcessor->syncProfile($userMetadata);\n\n if (\n $userToSearch instanceof User\n && $userProfile instanceof Profile\n && $userProfile->getUserId() === $userToSearch->getId()\n ) {\n $foundUser = $userProfile;\n }\n }\n\n return $foundUser;\n }\n\n public function syncProfileFields(): void\n {\n // Not used.\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $data = Cache::remember($this->team->id . $name . $count . $offset, 300, function () use ($name, $count, $offset) {\n $data = [];\n\n try {\n // If search phrase resembles phone number remove special symbols\n if (preg_match('/^([0-9\\s\\-\\+\\(\\)]*)$/', $name)) {\n $name = '+' . preg_replace('/[\\s\\-\\+\\(\\)]/', '', $name);\n }\n\n // Close do not provide a unified way to search, so we must hack our own.\n $objects = $this->client->get('lead', [\n 'query' => 'sort:date_updated name:(' . $name . ') or email:(' . $name . ') or phone:(' . $name . ')',\n '_limit' => $count, '_skip' => $offset,\n ]);\n } catch (\\GuzzleHttp\\Exception\\ServerException $exception) {\n throw new ServiceUnavailableException($exception->getMessage());\n }\n\n foreach ($objects['data'] as $object) {\n // We need a contact to dial it.\n if (empty($object['contacts'])) {\n continue;\n }\n\n foreach ($object['contacts'] as $contact) {\n $record = [\n 'crmId' => $contact['id'],\n 'crmUrl' => $this->generateProviderUrl($object['id'], 'account'),\n 'name' => $contact['name'],\n 'industry' => null,\n 'title' => $contact['title'],\n 'organization' => $object['display_name'],\n 'prospectType' => 'contact',\n 'phoneNumbers' => [],\n ];\n\n foreach ($contact['phones'] as $phone) {\n if ($phone['type'] === 'mobile') {\n $number = $this->buildContactMobilePhone(null, $phone['phone']);\n\n $record['phoneNumbers'][] = [\n 'number' => $number,\n 'nationalFormat' => phone_national(null, $number),\n 'type' => 'mobile',\n ];\n } else {\n $parsedNumber = $this->buildContactPhone(null, $phone['phone']);\n\n // Add phone number to record.\n if (empty($parsedNumber['phone']) === false) {\n $record['phoneNumbers'][] = [\n 'number' => $parsedNumber['phone'],\n 'nationalFormat' => phone_national(null, $parsedNumber['phone']),\n 'type' => 'phone',\n ];\n }\n }\n }\n\n $data[] = $record;\n }\n }\n\n return $data;\n });\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'lead_id' => $account->crm_provider_id,\n '_order_by' => '-date_updated',\n ];\n\n $onlyOpen = true;\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['_order_by'] = '-date_updated';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['_order_by'] = '-date_created';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['_order_by'] = 'date_created';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['_order_by'] = '-date_updated';\n $onlyOpen = false;\n }\n\n if ($onlyOpen) {\n $params['status_type__in'] = 'active,won';\n }\n\n $clOpportunities = $this->client->get('opportunity', $params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($clOpportunities['data'] as $clOpportunity) {\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', $clOpportunity['status_id'])\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $clOpportunity['status_id']);\n }\n\n $record = [\n 'crmId' => $clOpportunity['id'],\n 'name' => $clOpportunity['note'],\n 'value' => currency_format($clOpportunity['value'], $clOpportunity['value_currency']),\n 'won' => $stage->probability === 100.00,\n 'closed' => $clOpportunity['status_type'] !== 'active',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [],\n ];\n\n if ($ownerId && isset($clOpportunity['user_id']) && $clOpportunity['user_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = [];\n $crmId = null;\n\n if ($objectType === 'contact') {\n $contact = $this->syncContact($objectId);\n\n if ($contact && $contact->account_id) {\n $crmId = $contact->account->crm_provider_id;\n }\n } else {\n $crmId = $objectId;\n }\n\n if ($crmId) {\n $clTasks = $this->client->get('task', [\n 'lead_id' => $crmId,\n '_type' => 'lead',\n 'assigned_to' => $this->profile->crm_provider_id,\n 'is_complete' => 'false',\n '_order_by' => 'date',\n ]);\n\n foreach ($clTasks['data'] as $clTask) {\n $data[] = [\n 'crmId' => $clTask['id'],\n 'subject' => $clTask['text'],\n 'due' => $clTask['date'] ?? null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(email(email:\"' . $email . '\"))',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n foreach ($clContact['emails'] as $clEmail) {\n if ($email === $clEmail['email']) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(' . $phone . ')',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n foreach ($clContact['phones'] as $clPhone) {\n if ($phone === $clPhone['phone']) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n }\n }\n }\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $cacheKey = $this->getCacheKey($name, $userId);\n\n $result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {\n $clObject = $this->client->get('lead', [\n 'query' => 'sort:updated contact(name:\"' . $name . '\")',\n '_limit' => 1,\n ]);\n\n if ($clObject['total_results'] > 0) {\n foreach ($clObject['data'][0]['contacts'] as $clContact) {\n if ($clContact['name'] === $name || $clContact['display_name'] === $name) {\n $data = $this->convertCrmData($clContact['id'], $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n }\n }\n }\n\n return false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n protected function getCacheKey(string $object, ?int $userId = null): ?string\n {\n $key = $this->team->getId() . $object;\n $keySuffix = $this->getOwnerKeySuffix($userId);\n\n return $key . $keySuffix;\n }\n\n private function getOwnerKeySuffix(?int $userId = null): string\n {\n return $userId === null ? '' : (string) $userId;\n }\n\n private function convertCrmData(string $crmId, ?int $userId = null): array\n {\n $lead = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n $contact = $this->syncContact($crmId);\n if ($contact) {\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (Exception) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function mapStatus(string $status): string\n {\n switch ($status) {\n case Activity::STATUS_COMPLETED:\n case Activity::STATUS_IN_PROGRESS:\n case Activity::STATUS_FAILED:\n case Activity::STATUS_NO_ANSWER:\n case Activity::STATUS_BUSY:\n default:\n return $status;\n case Activity::STATUS_CANCELLED:\n return 'cancel';\n }\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $data = [\n '_type' => 'lead',\n 'lead_id' => $activity->account->crm_provider_id,\n 'assigned_to' => $this->profile->crm_provider_id,\n 'text' => $this->generateActivityDescription($activity),\n 'date' => $activity->getActualEndTime()->toDateString(),\n 'is_complete' => true,\n ];\n\n $this->logger->info('[Close CRM] Updating task', [\n 'activity' => $activity->id,\n 'crm_id' => $activity->crm_provider_id,\n 'data' => $data,\n ]);\n\n $this->client->put('task/' . $activity->crm_provider_id, $data);\n } else {\n // Just create an activity.\n $data = [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'direction' => $activity->getCrmType() === Activity::TYPE_SOFTPHONE ? 'outbound' : 'inbound',\n 'status' => $this->mapStatus($activity->getStatus()),\n 'note' => $this->generateActivityDescription($activity),\n 'duration' => $this->mapStatus($activity->getStatus()) !== 'cancel' ? $activity->duration : 0,\n 'phone' => $activity->to ? $activity->to->phone_number : null,\n ];\n\n $clActivity = $this->client->post('activity/call', $data);\n\n $this->logger->info('[Close CRM] Creating activity', [\n 'activity' => $activity->id,\n 'crm_id' => $clActivity['id'],\n 'data' => $data,\n 'response' => $clActivity,\n ]);\n\n $activity->crm_provider_id = $clActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n $response = $exception->getResponse();\n\n if ($response === null) {\n // Trying to debug weird cases where this is null.\n Sentry::captureException($exception);\n }\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n $clActivity = $this->client->post('activity/sms', [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'status' => $activity->getType() === Activity::TYPE_SMS_OUTBOUND ? 'sent' : 'inbox',\n 'text' => $this->generateActivityDescription($activity),\n 'remote_phone' => $activity->to ? $activity->to->phone_number : null,\n 'local_phone' => $activity->to ? $activity->to->phone_number : null,\n 'source' => 'Close.io',\n ]);\n\n $activity->crm_provider_id = $clActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n if ($activity->hasActivityType()) {\n $description = $activity->getActivityType()->getName() . PHP_EOL . PHP_EOL;\n }\n if ($activity->hasTitle()) {\n $description .= $activity->getTitle() . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->type === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $time = ($note->time > 3600) ? gmdate('H:i:s', $note->time) : gmdate('i:s', $note->time);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['name'])) {\n return null;\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::parse($fields['due_date']);\n $due = $formatDue->toDateTimeString();\n }\n\n $clTask = $this->client->post('task', [\n '_type' => 'lead',\n 'lead_id' => $activity->account->crm_provider_id,\n 'assigned_to' => $this->profile->crm_provider_id,\n 'text' => $fields['name'],\n 'date' => $due,\n 'is_complete' => false,\n ]);\n\n // We don't actually create a corresponding activity object on our side yet.\n return $clTask['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n if ($activity->account_id === null) {\n // We can only log to accounts (leads).\n return;\n }\n\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, self::NOTE_BODY_MAX_LENGTH);\n\n $clActivity = $this->client->post('activity/note', [\n 'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,\n 'created_by' => $this->profile->crm_provider_id,\n 'user_id' => $this->profile->crm_provider_id,\n 'note' => $transcripts,\n ]);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $clActivity['id'];\n $transcription->save();\n }\n\n public function parseObjectType(string $objectId): string\n {\n if (Str::startsWith($objectId, 'lead')) {\n return 'account';\n }\n\n if (Str::startsWith($objectId, 'cont')) {\n return 'contact';\n }\n\n if (Str::startsWith($objectId, 'oppo')) {\n return 'opportunity';\n }\n\n throw new InvalidArgumentException('Unsupported Object Type');\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n // This would never get invoked since we merge lead/accounts in Close.\n $this->client->put('lead/' . $crmObject->crm_provider_id, [\n 'status' => $stage->crm_provider_id,\n ]);\n } else {\n $this->client->put('opportunity/' . $crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $this->getClient()->updateObject($this->convertObjectTypeToResource($objectType), $objectId, $data);\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $convertedValue = $this->fieldValueConverter->convertToCrm(\n $this->config,\n $params['fieldName'],\n $params['fieldValue'],\n );\n\n if ($this->isCustomField($params['fieldName'])) {\n $params['fieldName'] = 'custom.' . $params['fieldName'];\n }\n\n $params['fieldValue'] = $convertedValue;\n\n return parent::prepareValueForUpdate($params);\n }\n\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->client->get($this->convertObjectTypeToResource($objectType) . '/' . $objectId);\n }\n\n /**\n *\n * @throws UnexpectedValueException\n */\n private function convertObjectTypeToResource(string $objectType): string\n {\n switch ($objectType) {\n case FieldData::OBJECT_OPPORTUNITY:\n return 'opportunity';\n\n case FieldData::OBJECT_CONTACT:\n return 'contact';\n\n case FieldData::OBJECT_ACCOUNT:\n return 'lead';\n\n case FieldData::OBJECT_TASK:\n return 'activity';\n\n default:\n throw new UnexpectedValueException('Unsupported object type \"' . $objectType . '\"');\n }\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.close.com/';\n $url = null;\n\n switch ($objectType) {\n case 'account':\n $url = $baseUrl . 'lead/' . $providerId;\n\n break;\n\n case 'contact':\n $contact = $this->config->contacts()->where('crm_provider_id', $providerId)->first();\n if ($contact && $contact->account_id) {\n $url = $baseUrl . 'lead/' . $contact->account->crm_provider_id;\n }\n\n break;\n\n default:\n // Sadly we can't deeplink to anything else in Close UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! $this->config->store_transcript) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n $client = $this->getClient();\n $task = $client->get('task/' . $crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Close] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (CloseException $e) {\n // Handle 404 responses from Close API\n if ($e->getResponseStatusCode() === 404) {\n $this->logger->info('[Close] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Close exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6754415607117048428
|
-9030663327281178587
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
8
39
5
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Close;
use Cache;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CloseInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\ServiceUnavailableException;
use Jiminny\Exceptions\UnexpectedCallException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Close\Processor\AccountProcessor;
use Jiminny\Services\Crm\Close\Processor\MetadataProcessor;
use Jiminny\Services\Crm\Close\Processor\OpportunityProcessor;
use Jiminny\Services\Crm\Close\Processor\StageProcessor;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\Metadata\OpportunityMetadata;
use Jiminny\Services\Crm\Metadata\ProfileMetadata;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Sentry;
use UnexpectedValueException;
class Service extends BaseService implements
CloseInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
SupportsObjectTypeParseInterface,
VerifyTaskExistsInterface
{
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private StandardFieldMetadata $standardFieldMetadata;
private MetadataProcessor $metadataProcessor;
private FieldValueConverter $fieldValueConverter;
private StageProcessor $stageProcessor;
private OpportunityProcessor $opportunityProcessor;
private AccountProcessor $accountProcessor;
public function __construct(
Client $client,
StandardFieldMetadata $standardFieldMetadata,
MetadataProcessor $metadataProcessor,
FieldValueConverter $fieldValueConverter,
StageProcessor $stageResolver,
OpportunityProcessor $opportunityProcessor,
AccountProcessor $accountProcessor,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
) {
parent::__construct();
$this->client = $client;
$this->standardFieldMetadata = $standardFieldMetadata;
$this->metadataProcessor = $metadataProcessor;
$this->fieldValueConverter = $fieldValueConverter;
$this->stageProcessor = $stageResolver;
$this->opportunityProcessor = $opportunityProcessor;
$this->accountProcessor = $accountProcessor;
}
public function getDisplayName(): string
{
return 'Close';
}
public function setConfiguration(Configuration $config): void
{
parent::setConfiguration($config);
$this->metadataProcessor->setConfiguration($config);
$this->stageProcessor->setConfiguration($config);
$this->opportunityProcessor->setConfiguration($config);
$this->accountProcessor->setConfiguration($config);
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
return $user->getTeam()->getOwner()->getSocialAccount(SocialAccount::PROVIDER_CLOSE);
}
private function getClient(): Client
{
if (! $this->client instanceof Client) {
throw new UnexpectedCallException('Client not set');
}
return $this->client;
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_OPPORTUNITY,
parent::OBJECT_CONTACT,
parent::OBJECT_ACCOUNT,
];
}
protected function getFields(string $crmObject): array
{
// not used
return [];
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Set up the activity field as the default Type.
/** @var Field $activityField */
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldData = FieldDefinitions::followupFieldsFilter();
foreach ($fieldData as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
/**
* @important Works only for custom fields
*/
public function syncField(Field $field): void
{
$resource = $this->convertObjectTypeToResource($field->getObjectType());
// We can only sync custom fields in this CRM.
if ($this->isCustomField($field->getCrmProviderId()) === false) {
return;
}
$crmField = $this->getClient()->fetchCustomFieldDefinition($resource, $field->getCrmProviderId());
$this->metadataProcessor->syncField($crmField);
}
private function isCustomField(string $fieldId): bool
{
return strpos($fieldId, 'cf_') === 0;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
// handled in syncFields()
return [];
}
/**
* @important We only support stages on the opportunity object
*
* @param string[]|null $types
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if (! $missingStageName) {
// This is taken care of by syncOrganization()
return null;
}
$stage = $this->stageProcessor->resolveFromStageId($missingStageName);
if ($stage instanceof Stage) {
return $stage;
}
$stageMetadata = $this->getClient()->fetchStage($missingStageName);
if (! $stageMetadata) {
$this->logger->error('Stage does not exist', [
'stage' => $missingStageName,
]);
return null;
}
return $this->stageProcessor->importStage($stageMetadata);
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
// Even though Close.io has the concept of "leads", they fit more into our concept of accounts.
return 0;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
// Not a supported entity.
return null;
}
/**
* @throws Exception
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
foreach ($this->getClient()->listAccounts($since) as $clAccount) {
// Only sync if previously imported.
if ($this->hasAccount($clAccount->getId())) {
$this->importAccount($clAccount);
$syncCount++;
}
}
} catch (Exception $exception) {
$this->logger->error('Account sync failed', [
'error' => $exception->getMessage(),
]);
throw $exception;
}
return $syncCount;
}
public function syncAccount(string $crmId): ?Account
{
return $this->accountProcessor->syncAccount($crmId);
}
private function importAccount($crmData): Account
{
return $this->accountProcessor->importAccountMetadata($crmData);
}
/**
* @throws CloseException
*/
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
$opportunities = [];
foreach ($strategies as $syncStrategy) {
$opportunitiesData = $syncStrategy->fetchOpportunities($parameters);
$opportunities[] = $opportunitiesData['data'];
if ($opportunitiesData['has_more']) {
$this->logger->info('[Close] Sync Opportunities - count warning', [
'team_id' => $this->config->getTeam()->getId(),
'total' => $opportunitiesData['total'],
'count' => $opportunitiesData['count'],
'skip' => $opportunitiesData['skip'],
'strategies_count' => count($strategies),
]);
}
}
$opportunities = array_merge(...$opportunities);
} catch (CrmException $exception) {
$this->logger->error('Fetching opportunity data failed', [
'team' => $this->getTeam()->getSlug(),
'error' => $exception->getMessage(),
]);
return 0;
}
foreach ($opportunities as $opportunityMetadata) {
try {
$this->importOpportunity($opportunityMetadata);
$syncCount++;
} catch (Exception $exception) {
$this->logger->warning('Opportunity sync failed', [
'opportunity' => $opportunityMetadata->getId(),
'error' => $exception->getMessage(),
]);
}
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->client,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = ['crm_id' => $crmId];
$opportunity = $strategy->fetchOpportunities($parameters);
if (empty($opportunity['data'])) {
return null;
}
return $this->importOpportunity($opportunity['data']);
}
private function importOpportunity(OpportunityMetadata $crmData): ?Opportunity
{
if (! $crmData->getLeadId()) {
$this->logger->warning('Opportunity does not have a lead ID', [
'opportunity' => $crmData->getId(),
]);
return null;
}
$account = $this->getConfiguration()
->accounts()
->where('crm_provider_id', $crmData->getLeadId())
->first();
if ($account === null) {
$account = $this->accountProcessor->syncAccount($crmData->getLeadId());
}
/** @var Profile $profile */
$profile = $this->getConfiguration()
->profiles()
->where('crm_provider_id', $crmData->getUserId())
->first();
$userId = $profile?->getUserId() ?? $account?->getUserId();
if ($userId === null) {
$this->logger->error('[Close] | Skip import, no user_id found', [
'id' => $crmData->getId(),
]);
return null;
}
$stage = $this->getConfiguration()
->stages()
->where('crm_provider_id', $crmData->getStageId())
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData->getStageId());
}
return $this->opportunityProcessor->import($crmData, $account, $stage, $profile);
}
/**
* @param array<string,string> $crmData
* @param string[] $crmFields
*/
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// handled in importOpportunity
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
/** No way to sync today.
$clContacts = $this->client->get('lead', [
'date_updated__gte' => $since->toDateString(),
'_order_by' => '-date_updated',
]);
foreach ($clContacts as $clContact) {
// Only sync if previously imported.
if ($this->hasContact($clContact['id'])) {
$this->importContact($clContact);
$syncCount++;
}
}
**/
} catch (Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
try {
$clContact = $this->client->get('contact/' . $crmId);
} catch (HttpNotFoundException $exception) {
return null;
}
return $this->importContact($clContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['lead_id']) {
$account = $this->team
->accounts()
->where('crm_provider_id', $crmData['lead_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['lead_id']);
}
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phones'] as $phoneNumber) {
if ($phoneNumber['type'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone(null, $phoneNumber['phone']);
} else {
$parsedNumber = $this->buildContactPhone(null, $phoneNumber['phone']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['updated_by'])->first();
$data = [
'account_id' => $account->id ?? null,
'team_id' => $this->team->id,
'user_id' => $profile?->user_id,
'owner_id' => $crmData['updated_by'],
'name' => $crmData['name'] ?? 'Unknown',
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => mb_strimwidth($crmData['title'] ?? '', 0, 128),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name'] ?? 'Unknown'
),
'remotely_created_at' => Carbon::parse($crmData['date_created']),
];
/** @var Contact */
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
public function syncOrganization(): void
{
$organisation = $this->getClient()->fetchOrganisation();
$this->metadataProcessor->syncOrganisation($organisation);
foreach ($organisation->getPipelines() as $pipelineMetadata) {
$this->metadataProcessor->syncPipeline($pipelineMetadata);
}
}
private function syncStandardFields(): void
{
// Currently we sync only opportunity fields
$stages = $this->getClient()->listStages();
foreach ($this->standardFieldMetadata->opportunity($stages) as $fieldMetadata) {
$this->metadataProcessor->syncField($fieldMetadata);
}
$this->config->save();
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$objectType = $this->convertObjectTypeToResource($fieldType);
$currentFields = $this->getClient()->listCustomFieldDefinitions($objectType);
foreach ($currentFields as $fieldMetadata) {
$this->metadataProcessor->syncField($fieldMetadata);
}
}
$this->config->save();
}
public function syncProfiles(?User $userToSearch = null): ?Profile
{
/*
* Fetch the profile of the user from the database
* Then fetch the user metadata from Close and update it
* In case there's no profile for the user, proceed with syncing all users
*/
$foundUser = null;
if ($userToSearch) {
$profile = $userToSearch->getProfile();
if ($profile instanceof Profile) {
$crmProviderId = $profile->getCrmProviderId();
if ($crmProviderId) {
$profileMetadata = $this->getClient()->fetchUser($crmProviderId);
if (! $profileMetadata instanceof ProfileMetadata) {
return null;
}
return $this->metadataProcessor->syncProfile($profileMetadata);
}
}
}
foreach ($this->getClient()->listUsers() as $userMetadata) {
$userProfile = $this->metadataProcessor->syncProfile($userMetadata);
if (
$userToSearch instanceof User
&& $userProfile instanceof Profile
&& $userProfile->getUserId() === $userToSearch->getId()
) {
$foundUser = $userProfile;
}
}
return $foundUser;
}
public function syncProfileFields(): void
{
// Not used.
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$data = Cache::remember($this->team->id . $name . $count . $offset, 300, function () use ($name, $count, $offset) {
$data = [];
try {
// If search phrase resembles phone number remove special symbols
if (preg_match('/^([0-9\s\-\+\(\)]*)$/', $name)) {
$name = '+' . preg_replace('/[\s\-\+\(\)]/', '', $name);
}
// Close do not provide a unified way to search, so we must hack our own.
$objects = $this->client->get('lead', [
'query' => 'sort:date_updated name:(' . $name . ') or email:(' . $name . ') or phone:(' . $name . ')',
'_limit' => $count, '_skip' => $offset,
]);
} catch (\GuzzleHttp\Exception\ServerException $exception) {
throw new ServiceUnavailableException($exception->getMessage());
}
foreach ($objects['data'] as $object) {
// We need a contact to dial it.
if (empty($object['contacts'])) {
continue;
}
foreach ($object['contacts'] as $contact) {
$record = [
'crmId' => $contact['id'],
'crmUrl' => $this->generateProviderUrl($object['id'], 'account'),
'name' => $contact['name'],
'industry' => null,
'title' => $contact['title'],
'organization' => $object['display_name'],
'prospectType' => 'contact',
'phoneNumbers' => [],
];
foreach ($contact['phones'] as $phone) {
if ($phone['type'] === 'mobile') {
$number = $this->buildContactMobilePhone(null, $phone['phone']);
$record['phoneNumbers'][] = [
'number' => $number,
'nationalFormat' => phone_national(null, $number),
'type' => 'mobile',
];
} else {
$parsedNumber = $this->buildContactPhone(null, $phone['phone']);
// Add phone number to record.
if (empty($parsedNumber['phone']) === false) {
$record['phoneNumbers'][] = [
'number' => $parsedNumber['phone'],
'nationalFormat' => phone_national(null, $parsedNumber['phone']),
'type' => 'phone',
];
}
}
}
$data[] = $record;
}
}
return $data;
});
return $data;
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'lead_id' => $account->crm_provider_id,
'_order_by' => '-date_updated',
];
$onlyOpen = true;
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['_order_by'] = '-date_updated';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['_order_by'] = '-date_created';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['_order_by'] = 'date_created';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['_order_by'] = '-date_updated';
$onlyOpen = false;
}
if ($onlyOpen) {
$params['status_type__in'] = 'active,won';
}
$clOpportunities = $this->client->get('opportunity', $params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($clOpportunities['data'] as $clOpportunity) {
$stage = $this->config
->stages()
->where('crm_provider_id', $clOpportunity['status_id'])
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $clOpportunity['status_id']);
}
$record = [
'crmId' => $clOpportunity['id'],
'name' => $clOpportunity['note'],
'value' => currency_format($clOpportunity['value'], $clOpportunity['value_currency']),
'won' => $stage->probability === 100.00,
'closed' => $clOpportunity['status_type'] !== 'active',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [],
];
if ($ownerId && isset($clOpportunity['user_id']) && $clOpportunity['user_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
if (! empty($ownerData)) {
return $ownerData;
}
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = [];
$crmId = null;
if ($objectType === 'contact') {
$contact = $this->syncContact($objectId);
if ($contact && $contact->account_id) {
$crmId = $contact->account->crm_provider_id;
}
} else {
$crmId = $objectId;
}
if ($crmId) {
$clTasks = $this->client->get('task', [
'lead_id' => $crmId,
'_type' => 'lead',
'assigned_to' => $this->profile->crm_provider_id,
'is_complete' => 'false',
'_order_by' => 'date',
]);
foreach ($clTasks['data'] as $clTask) {
$data[] = [
'crmId' => $clTask['id'],
'subject' => $clTask['text'],
'due' => $clTask['date'] ?? null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(email(email:"' . $email . '"))',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
foreach ($clContact['emails'] as $clEmail) {
if ($email === $clEmail['email']) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : null;
}
}
}
}
return null;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array
{
// Check if the user is internal.
$teamMember = $this->team->users()->where('phone', $phone)->exists();
// Skip the attendee if internal.
if ($teamMember === false) {
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(' . $phone . ')',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
foreach ($clContact['phones'] as $clPhone) {
if ($phone === $clPhone['phone']) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : null;
}
}
}
}
}
return null;
}
/**
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
* }
*/
public function matchByName(string $name, ?int $userId = null): ?array
{
// Don't waste time searching for single character strings.
if (\strlen($name) <= 1) {
return null;
}
$cacheKey = $this->getCacheKey($name, $userId);
$result = Cache::remember($cacheKey, 60, function () use ($name, $userId) {
$clObject = $this->client->get('lead', [
'query' => 'sort:updated contact(name:"' . $name . '")',
'_limit' => 1,
]);
if ($clObject['total_results'] > 0) {
foreach ($clObject['data'][0]['contacts'] as $clContact) {
if ($clContact['name'] === $name || $clContact['display_name'] === $name) {
$data = $this->convertCrmData($clContact['id'], $userId);
return ! empty(array_filter($data)) ? $data : false;
}
}
}
return false;
});
return is_array($result) ? $result : null;
}
protected function getCacheKey(string $object, ?int $userId = null): ?string
{
$key = $this->team->getId() . $object;
$keySuffix = $this->getOwnerKeySuffix($userId);
return $key . $keySuffix;
}
private function getOwnerKeySuffix(?int $userId = null): string
{
return $userId === null ? '' : (string) $userId;
}
private function convertCrmData(string $crmId, ?int $userId = null): array
{
$lead = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
$contact = $this->syncContact($crmId);
if ($contact) {
$account = $contact->account;
if ($contact->country_code) {
$countryCode = $contact->country_code;
} elseif ($account) {
$countryCode = $account->country_code;
}
try {
$cpOpportunities = $this->findOpportunities(
$account?->crm_provider_id,
$contact->crm_provider_id,
$userId,
);
if (! empty($cpOpportunities)) {
// Persist this remote object.
$opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);
$stage = $opportunity?->getStage();
}
} catch (Exception) {
// Nothing to see here.
}
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
public function saveActivity(Activity $activity): Activity
{
switch ($activity->type) {
case Activity::TYPE_CONFERENCE:
case Activity::TYPE_SOFTPHONE:
case Activity::TYPE_SOFTPHONE_INBOUND:
$activity = $this->buildCallPayload($activity);
break;
case Activity::TYPE_SMS_INBOUND:
case Activity::TYPE_SMS_OUTBOUND:
$activity = $this->buildTextMessagePayload($activity);
break;
}
return $activity;
}
private function mapStatus(string $status): string
{
switch ($status) {
case Activity::STATUS_COMPLETED:
case Activity::STATUS_IN_PROGRESS:
case Activity::STATUS_FAILED:
case Activity::STATUS_NO_ANSWER:
case Activity::STATUS_BUSY:
default:
return $status;
case Activity::STATUS_CANCELLED:
return 'cancel';
}
}
/**
* @throws CrmException
*/
private function buildCallPayload(Activity $activity): Activity
{
try {
if ($activity->crm_provider_id) {
// The activity should be logged under the existing Task (not Activity).
$data = [
'_type' => 'lead',
'lead_id' => $activity->account->crm_provider_id,
'assigned_to' => $this->profile->crm_provider_id,
'text' => $this->generateActivityDescription($activity),
'date' => $activity->getActualEndTime()->toDateString(),
'is_complete' => true,
];
$this->logger->info('[Close CRM] Updating task', [
'activity' => $activity->id,
'crm_id' => $activity->crm_provider_id,
'data' => $data,
]);
$this->client->put('task/' . $activity->crm_provider_id, $data);
} else {
// Just create an activity.
$data = [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'direction' => $activity->getCrmType() === Activity::TYPE_SOFTPHONE ? 'outbound' : 'inbound',
'status' => $this->mapStatus($activity->getStatus()),
'note' => $this->generateActivityDescription($activity),
'duration' => $this->mapStatus($activity->getStatus()) !== 'cancel' ? $activity->duration : 0,
'phone' => $activity->to ? $activity->to->phone_number : null,
];
$clActivity = $this->client->post('activity/call', $data);
$this->logger->info('[Close CRM] Creating activity', [
'activity' => $activity->id,
'crm_id' => $clActivity['id'],
'data' => $data,
'response' => $clActivity,
]);
$activity->crm_provider_id = $clActivity['id'];
$activity->save();
}
} catch (ClientException $exception) {
$response = $exception->getResponse();
if ($response === null) {
// Trying to debug weird cases where this is null.
Sentry::captureException($exception);
}
$responseBody = $response->getBody();
$message = $responseBody;
$errorCode = $response->getStatusCode();
$jsonResponse = json_decode($responseBody, true);
if (isset($jsonResponse[0]['message'])) {
$message = $jsonResponse[0]['message'];
}
throw new CrmException($message, $errorCode);
}
return $activity;
}
private function buildTextMessagePayload(Activity $activity): Activity
{
$clActivity = $this->client->post('activity/sms', [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'contact_id' => $activity->contact_id ? $activity->contact->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'status' => $activity->getType() === Activity::TYPE_SMS_OUTBOUND ? 'sent' : 'inbox',
'text' => $this->generateActivityDescription($activity),
'remote_phone' => $activity->to ? $activity->to->phone_number : null,
'local_phone' => $activity->to ? $activity->to->phone_number : null,
'source' => 'Close.io',
]);
$activity->crm_provider_id = $clActivity['id'];
$activity->save();
return $activity;
}
private function generateActivityDescription(Activity $activity): string
{
$description = '';
switch ($activity->type) {
case Activity::TYPE_SOFTPHONE:
case Activity::TYPE_SOFTPHONE_INBOUND:
case Activity::TYPE_CONFERENCE:
if ($activity->hasActivityType()) {
$description = $activity->getActivityType()->getName() . PHP_EOL . PHP_EOL;
}
if ($activity->hasTitle()) {
$description .= $activity->getTitle() . PHP_EOL;
}
if ($activity->hasReasonCodeBotKicked()) {
$description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;
// When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.
} elseif ($activity->hasReasonCodeNotCompliant()) {
$description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;
} elseif ($activity->canReviewActivity()) {
$playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);
$description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;
}
if ($activity->type === Activity::TYPE_CONFERENCE) {
$description .= 'Attendees:'
. PHP_EOL
. (new FilterJoinedParticipants())->toString($activity);
}
if (\count($activity->notes) > 0) {
$description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;
foreach ($activity->notes as $note) {
$time = ($note->time > 3600) ? gmdate('H:i:s', $note->time) : gmdate('i:s', $note->time);
$description .= $time . ' ' . $note->note . PHP_EOL;
}
}
// Get all private messages.
$messages = $activity->messages()
->where('is_private', 1)
->orderBy('created_at', 'asc');
if ($messages->count() > 0) {
$description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;
foreach ($messages->get() as $message) {
$description .= $message->participant->name . ': ' . $message->message . PHP_EOL;
}
}
// Get all public messages.
$messages = $activity->messages()
->where('is_private', 0)
->orderBy('created_at', 'asc');
if ($messages->count() > 0) {
$description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;
foreach ($messages->get() as $message) {
$description .= $message->participant->name . ': ' . $message->message . PHP_EOL;
}
}
if ($activity->summary) {
$description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;
}
break;
case Activity::TYPE_SMS_INBOUND:
case Activity::TYPE_SMS_OUTBOUND:
$description = $activity->description;
break;
}
return $description;
}
public function saveFollowupActivity(Activity $activity, array $fields): ?string
{
// This is the user provided activity subject field.
if (empty($fields['name'])) {
return null;
}
$due = null;
if (empty($fields['due_date']) === false) {
$formatDue = Carbon::parse($fields['due_date']);
$due = $formatDue->toDateTimeString();
}
$clTask = $this->client->post('task', [
'_type' => 'lead',
'lead_id' => $activity->account->crm_provider_id,
'assigned_to' => $this->profile->crm_provider_id,
'text' => $fields['name'],
'date' => $due,
'is_complete' => false,
]);
// We don't actually create a corresponding activity object on our side yet.
return $clTask['id'];
}
/**
* Store transcripts as note.
*
* @throws Exception
*/
public function createTranscriptNotes(Activity $activity): void
{
if ($activity->account_id === null) {
// We can only log to accounts (leads).
return;
}
// Generate activity transcription.
$transcriptionData = $this->generateTranscription($activity);
// Truncate Notes with max notes length because transcription text could be very long.
$transcripts = mb_strimwidth($transcriptionData, 0, self::NOTE_BODY_MAX_LENGTH);
$clActivity = $this->client->post('activity/note', [
'lead_id' => $activity->account_id ? $activity->account->crm_provider_id : null,
'created_by' => $this->profile->crm_provider_id,
'user_id' => $this->profile->crm_provider_id,
'note' => $transcripts,
]);
// Store CRM Activity ID in transcription.
$transcription = $activity->getTranscription();
$transcription->crm_activity_id = $clActivity['id'];
$transcription->save();
}
public function parseObjectType(string $objectId): string
{
if (Str::startsWith($objectId, 'lead')) {
return 'account';
}
if (Str::startsWith($objectId, 'cont')) {
return 'contact';
}
if (Str::startsWith($objectId, 'oppo')) {
return 'opportunity';
}
throw new InvalidArgumentException('Unsupported Object Type');
}
/**
* @inheritdoc
*/
public function updateStage($crmObject, Stage $stage): void
{
if ($crmObject instanceof Lead) {
// This would never get invoked since we merge lead/accounts in Close.
$this->client->put('lead/' . $crmObject->crm_provider_id, [
'status' => $stage->crm_provider_id,
]);
} else {
$this->client->put('opportunity/' . $crmObject->crm_provider_id, [
'status_id' => $stage->crm_provider_id,
]);
}
}
public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void
{
$this->getClient()->updateObject($this->convertObjectTypeToResource($objectType), $objectId, $data);
}
public function prepareValueForUpdate(array $params): array
{
$convertedValue = $this->fieldValueConverter->convertToCrm(
$this->config,
$params['fieldName'],
$params['fieldValue'],
);
if ($this->isCustomField($params['fieldName'])) {
$params['fieldName'] = 'custom.' . $params['fieldName'];
}
$params['fieldValue'] = $convertedValue;
return parent::prepareValueForUpdate($params);
}
public function getRecord(string $objectType, string $objectId, array $fields = []): array
{
return $this->client->get($this->convertObjectTypeToResource($objectType) . '/' . $objectId);
}
/**
*
* @throws UnexpectedValueException
*/
private function convertObjectTypeToResource(string $objectType): string
{
switch ($objectType) {
case FieldData::OBJECT_OPPORTUNITY:
return 'opportunity';
case FieldData::OBJECT_CONTACT:
return 'contact';
case FieldData::OBJECT_ACCOUNT:
return 'lead';
case FieldData::OBJECT_TASK:
return 'activity';
default:
throw new UnexpectedValueException('Unsupported object type "' . $objectType . '"');
}
}
public function generateProviderUrl(string $providerId, string $objectType): ?string
{
$baseUrl = 'https://app.close.com/';
$url = null;
switch ($objectType) {
case 'account':
$url = $baseUrl . 'lead/' . $providerId;
break;
case 'contact':
$contact = $this->config->contacts()->where('crm_provider_id', $providerId)->first();
if ($contact && $contact->account_id) {
$url = $baseUrl . 'lead/' . $contact->account->crm_provider_id;
}
break;
default:
// Sadly we can't deeplink to anything else in Close UI.
$url = null;
}
return $url;
}
/**
* Generate transcription for the activity.
*/
private function generateTranscription(Activity $activity): string
{
if (! $this->config->store_transcript) {
// If sending transcription to activity toggle is disabled
return '';
}
return $this->transcriptionService
->findTranscriptionByActivity($activity)
->map(static function (array $transcriptionSegment): string {
return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];
})
->implode(PHP_EOL);
}
public function verifyTaskExists(Activity $activity): bool
{
$crmProviderId = $activity->getCrmProviderId();
$cacheKey = "crm_task_exists:{$this->config->getId()}:$crmProviderId";
return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {
try {
$client = $this->getClient();
$task = $client->get('task/' . $crmProviderId);
return ! empty($task);
} catch (HttpNotFoundException) {
// Task not found in CRM - this is expected and permanent
$this->logger->info('[Close] Task not found during verification', [
'task_id' => $crmProviderId,
'config_id' => $this->config->getId(),
]);
...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55221
|
NULL
|
0
|
2026-05-18T13:57:46.520143+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779112666520_m2.jpg...
|
PhpStorm
|
faVsco.js – Crm/…/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorFV faVsco. PhostormVIewINavicarecodeLaravelKeractorFV faVsco.js°9 master k >ProiectRinaCentralVideoSalesforceIm Salesloft> D Talkdeskm TeamsD Telus>D Twilio>@ TwilioFlex_ I willorlexDireet• _ I Willo Videc_Uploader› _ VonagewxantDZ00ПZoomBot|> ZoomPhoneC) ActivitvcrmFieldsResolver.ohpC) ActivitvLoaService.oho© ActivitvProviderClient.ohp(C) ActivitvProviderRedistrv.ohoC. ActivitvProviderService.ohv© CallDenormalizerRegistry.phpC) [EMAIL]© DatalmportHandlerInterface.php© MeetingBotService.php© ParticipantConsentService.php(c) DarticinanteService nhnT PecnonceValidation Trait nhnT SalesforceGetUserTrait.php- S/DenormaliserMainCrmDatalrait.onp@ TrackRecordinoFllesizeservice.one©1rаскkecoraingsizetntorcer.onpT ValidateEmitProspectEventTrait.phpC AjReports0 AvatarMColondar0 Conferencem Crm> C Bullhorn• D CloseOnoortunitvsvncstrateav• ProcessonProspectSearchStrateav• M TranslatorC) Client.ohr() CloseSxceotion.ohoC) FieldDefinitions.onvc) SieldValueConverter ohn•) Service nhnC) StandardFioldMetadata nhn> MConnen© SoftPhoneManager.phpC) CoreUserRequest.pnp© CoreUser.php© ACtivity/.../Service.php©Crm/…../Service.php Xclass Service extends BaseService 1mpLements* 48 439 M5 ^248244 6t749255 @>284285 0>294 6t>300 F303 6326 6t >336339 61)oublic tunction suncreldcrield Srleld: vo1d$crmField = $this->getClient->fetchCustomFieldDefinition(Sresource, $field->getCrmProviderIdsch1s->mecadacarrocessor->syncrielascrmrlelamprivate function isCustomField(string $fieldId): boolf...}* oinheritdocpublic function importPicklistValues(Field $field): array{...}29 Ф >34 0 >* Oimportant We only support stages on the opportunity object45 đ >* Aparam strinalnul Stunesnublic function imnortStades@arrav Stvnes = null. Ostrina SmissinoStageName = nulb): ?Stade.....Т119* @inheritdocdnato rntle onatosescarean sare, fereten fo natl, Pertng deneortail e mn):* oinertcdoc1146 Gpublic function syncLead(string ScrmId): ?Lead{...}151 C* athrows Except1onpublic function svncAccounts(Carbon Ssince. ?Carbon $to = null): int{...}public function syncAccount(string $crmId): ?Account(...}1 usageorivate function importAccount(ScrmData)• Account!...}* athrows Mnsesycentionpublic function syncOpportunities(array $parameters, ?string $strategy = null): int{...}cter' hac heon rectored /l Pollback II Confiaure (todav 14-19)= custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]© CoachingFeedbackCoachUserln.php Xstohedeclare(scrict_cypes=l)nnamespace Jiminny Component Activ1tySearch rilterbetin1t1on*› use ...final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface1usadeorivate const int No GROUP 10 = 9993 usagesorivate UserRenository SuserRenository:public function __construct(UserRepository $userRepository)f...hpublic function shouldApplyQueries: boolf...}public function getQueries: FilterDefinitionQueryCollection{...}public function toArray@: array{...;private function getOptions(): array{...}public function getValue®: array{...}private function getDefaultValue@: array{...}public function aetValidationRules(2strina Sorefix = null): arravs...?public function aetSortOrder@: intf...}public function shouldBeIncluded(Team $team): bool{...}[Platform] Refinemen... 3 m left100% 2• Mon 18 May 16:57:45U AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for methodw9/ 10 tacke done• Write unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations.4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabled•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ @ ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ueer/M PoleAttr.nhn +17-ites/User/ ẞ RoleAttrTest.nhn +224* Reiect alliiAccent alliAsk anvthina (&4-L)« Code SWF-1.6WN Windsurf Teamo164•6UTE.8io 4 spaces...
|
NULL
|
-2376477822431713534
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorFV faVsco. PhostormVIewINavicarecodeLaravelKeractorFV faVsco.js°9 master k >ProiectRinaCentralVideoSalesforceIm Salesloft> D Talkdeskm TeamsD Telus>D Twilio>@ TwilioFlex_ I willorlexDireet• _ I Willo Videc_Uploader› _ VonagewxantDZ00ПZoomBot|> ZoomPhoneC) ActivitvcrmFieldsResolver.ohpC) ActivitvLoaService.oho© ActivitvProviderClient.ohp(C) ActivitvProviderRedistrv.ohoC. ActivitvProviderService.ohv© CallDenormalizerRegistry.phpC) [EMAIL]© DatalmportHandlerInterface.php© MeetingBotService.php© ParticipantConsentService.php(c) DarticinanteService nhnT PecnonceValidation Trait nhnT SalesforceGetUserTrait.php- S/DenormaliserMainCrmDatalrait.onp@ TrackRecordinoFllesizeservice.one©1rаскkecoraingsizetntorcer.onpT ValidateEmitProspectEventTrait.phpC AjReports0 AvatarMColondar0 Conferencem Crm> C Bullhorn• D CloseOnoortunitvsvncstrateav• ProcessonProspectSearchStrateav• M TranslatorC) Client.ohr() CloseSxceotion.ohoC) FieldDefinitions.onvc) SieldValueConverter ohn•) Service nhnC) StandardFioldMetadata nhn> MConnen© SoftPhoneManager.phpC) CoreUserRequest.pnp© CoreUser.php© ACtivity/.../Service.php©Crm/…../Service.php Xclass Service extends BaseService 1mpLements* 48 439 M5 ^248244 6t749255 @>284285 0>294 6t>300 F303 6326 6t >336339 61)oublic tunction suncreldcrield Srleld: vo1d$crmField = $this->getClient->fetchCustomFieldDefinition(Sresource, $field->getCrmProviderIdsch1s->mecadacarrocessor->syncrielascrmrlelamprivate function isCustomField(string $fieldId): boolf...}* oinheritdocpublic function importPicklistValues(Field $field): array{...}29 Ф >34 0 >* Oimportant We only support stages on the opportunity object45 đ >* Aparam strinalnul Stunesnublic function imnortStades@arrav Stvnes = null. Ostrina SmissinoStageName = nulb): ?Stade.....Т119* @inheritdocdnato rntle onatosescarean sare, fereten fo natl, Pertng deneortail e mn):* oinertcdoc1146 Gpublic function syncLead(string ScrmId): ?Lead{...}151 C* athrows Except1onpublic function svncAccounts(Carbon Ssince. ?Carbon $to = null): int{...}public function syncAccount(string $crmId): ?Account(...}1 usageorivate function importAccount(ScrmData)• Account!...}* athrows Mnsesycentionpublic function syncOpportunities(array $parameters, ?string $strategy = null): int{...}cter' hac heon rectored /l Pollback II Confiaure (todav 14-19)= custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]© CoachingFeedbackCoachUserln.php Xstohedeclare(scrict_cypes=l)nnamespace Jiminny Component Activ1tySearch rilterbetin1t1on*› use ...final class CoachingFeedbackCoachUserIn extends FilterDefinition implements ValidatedFilterDefinitionInterface1usadeorivate const int No GROUP 10 = 9993 usagesorivate UserRenository SuserRenository:public function __construct(UserRepository $userRepository)f...hpublic function shouldApplyQueries: boolf...}public function getQueries: FilterDefinitionQueryCollection{...}public function toArray@: array{...;private function getOptions(): array{...}public function getValue®: array{...}private function getDefaultValue@: array{...}public function aetValidationRules(2strina Sorefix = null): arravs...?public function aetSortOrder@: intf...}public function shouldBeIncluded(Team $team): bool{...}[Platform] Refinemen... 3 m left100% 2• Mon 18 May 16:57:45U AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for methodw9/ 10 tacke done• Write unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations.4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabled•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ @ ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ueer/M PoleAttr.nhn +17-ites/User/ ẞ RoleAttrTest.nhn +224* Reiect alliiAccent alliAsk anvthina (&4-L)« Code SWF-1.6WN Windsurf Teamo164•6UTE.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
55107
|
NULL
|
0
|
2026-05-18T13:52:16.054169+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779112336054_m2.jpg...
|
Firefox
|
Meet - [Platform] Refinement 🔍 — Work
|
1
|
meet.google.com/cxs-eips-npt?authuser=lukas.kovali meet.google.com/cxs-eips-npt?authuser=lukas.kovalik%40jiminny.com...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Meet - [Platform] Refinement 🔍
Close tab
New Tab
O Meet - [Platform] Refinement 🔍
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Nikolay Yankov (Presenting)
Nikolay Yankov (Presenting)
People
6
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Unpin Nikolay Yankov's presentation from your main screen
You can't unmute someone else's presentation
More options for Nikolay Yankov
Zoom in
Open in new window
Enter Full Screen
Pin Galya Dimitrova to your main screen
Mute Galya Dimitrova's microphone
More options for Galya Dimitrova
Galya Dimitrova
Pin Nikolay Yankov to your main screen
You can't unmute someone else
More options for Nikolay Yankov
Nikolay Yankov
Pin Aneliya Angelova to your main screen
You can't unmute someone else
More options for Aneliya Angelova
Aneliya Angelova
Pin Nikolay Ivanov to your main screen
You can't unmute someone else
More options for Nikolay Ivanov
Nikolay Ivanov
You’re continuously framed
Backgrounds and effects
More options for Lukas Kovalik
Lukas Kovalik
Others might see more of your background. Click to view your full video.
4:52
PM
[Platform] Refinement 🔍
[Platform] Refinement 🔍
Audio settings
Turn on microphone
Video settings
Turn off camera
Nikolay Yankov is presenting
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Meet - [Platform] Refinement 🔍","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.016123671,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.27094415,"top":1.0,"width":0.004986702,"height":-0.051875472},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.27310506,"top":1.0,"width":0.010638298,"height":-0.086193085},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Nikolay Yankov (Presenting)","depth":12,"bounds":{"left":0.30634972,"top":1.0,"width":0.059507977,"height":-0.072625756},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Nikolay Yankov (Presenting)","depth":13,"bounds":{"left":0.30634972,"top":1.0,"width":0.059507977,"height":-0.07342374},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"People","depth":15,"bounds":{"left":0.69481385,"top":1.0,"width":0.019614361,"height":-0.06424582},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":22,"bounds":{"left":0.7081117,"top":1.0,"width":0.0023271276,"height":-0.072625756},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Take notes with Gemini","depth":14,"bounds":{"left":0.71708775,"top":1.0,"width":0.011968086,"height":-0.06424582},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Take notes with Gemini","depth":17,"bounds":{"left":0.7184175,"top":1.0,"width":0.043550532,"height":-0.072625756},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini","depth":17,"bounds":{"left":0.7330452,"top":1.0,"width":0.013464096,"height":-0.072625756},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Gemini","depth":17,"bounds":{"left":0.73204786,"top":1.0,"width":0.011303191,"height":-0.065043926},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unpin Nikolay Yankov's presentation from your main screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"You can't unmute someone else's presentation","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Nikolay Yankov","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Zoom in","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open in new window","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Enter Full Screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Pin Galya Dimitrova to your main screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Mute Galya Dimitrova's microphone","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Galya Dimitrova","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Galya Dimitrova","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Pin Nikolay Yankov to your main screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"You can't unmute someone else","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Nikolay Yankov","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Yankov","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Pin Aneliya Angelova to your main screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"You can't unmute someone else","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Aneliya Angelova","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Aneliya Angelova","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Pin Nikolay Ivanov to your main screen","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"You can't unmute someone else","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Nikolay Ivanov","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"You’re continuously framed","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Backgrounds and effects","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options for Lukas Kovalik","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Lukas Kovalik","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Others might see more of your background. Click to view your full video.","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:52","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PM","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"[Platform] Refinement 🔍","depth":12,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[Platform] Refinement 🔍","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Audio settings","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on microphone","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXButton","text":"Video settings","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn off camera","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Nikolay Yankov is presenting","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Send a reaction","depth":12,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Turn on captions","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Raise hand (ctrl + ⌘ + h)","depth":12,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More options","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Leave call","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Meeting details","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat with everyone","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Meeting tools","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4843936129398188852
|
-8590422237931513808
|
idle
|
hybrid
|
NULL
|
Meet - [Platform] Refinement 🔍
Close tab
New Tab
O Meet - [Platform] Refinement 🔍
Close tab
New Tab
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Customize sidebar
Nikolay Yankov (Presenting)
Nikolay Yankov (Presenting)
People
6
Take notes with Gemini
Take notes with Gemini
Gemini
Gemini
Unpin Nikolay Yankov's presentation from your main screen
You can't unmute someone else's presentation
More options for Nikolay Yankov
Zoom in
Open in new window
Enter Full Screen
Pin Galya Dimitrova to your main screen
Mute Galya Dimitrova's microphone
More options for Galya Dimitrova
Galya Dimitrova
Pin Nikolay Yankov to your main screen
You can't unmute someone else
More options for Nikolay Yankov
Nikolay Yankov
Pin Aneliya Angelova to your main screen
You can't unmute someone else
More options for Aneliya Angelova
Aneliya Angelova
Pin Nikolay Ivanov to your main screen
You can't unmute someone else
More options for Nikolay Ivanov
Nikolay Ivanov
You’re continuously framed
Backgrounds and effects
More options for Lukas Kovalik
Lukas Kovalik
Others might see more of your background. Click to view your full video.
4:52
PM
[Platform] Refinement 🔍
[Platform] Refinement 🔍
Audio settings
Turn on microphone
Video settings
Turn off camera
Nikolay Yankov is presenting
Send a reaction
Turn on captions
Raise hand (ctrl + ⌘ + h)
More options
Leave call
Meeting details
Chat with everyone
Meeting tools
rireroCaltVIeWMIstorybookmarksProtllesWindow••0 0You are currently impersonating Nikolay Yankov <)Platform Sprint 4 Q2 - Platform TeOrganization SettingsPlavbooks & Coaching Frameworks (?Service-Desk - Queues - PlatfornGeneralw Usage | WindsurfQUsersAllow owner's role to be selectedTeams• [Vasil] test playbook|Pipelines - jiminny/appIntegrations> • Kick-Off Meeting9(SRD-6848] Sidekick SMS issue1I0Job TitlesiCloudWatch I us-east-2ActivityCloudWatch | us-east-2RecordingSJiminnyAl Contexts) Jiminny\Exceptions|SocialAccountAl Automation BETACAllow owner's role to be selected vSidekickY [SRD-6862] 'User does not have aDeal InsightsNew TabVocabulary(JY-209121 Fallback mechanism fcTopicsS MIY-207711 Call Scorina filter for &Key Words ScoringPlavbooks & Coaching FrameworksT [JY-20878] SCIM > Allow customeNotitications- WJY-208791 Enable users to use thSettingsProject Phoenix - Figma7 (JY-208471 Users can filter Score:LIY-205341 Al Call Scorina quick al— New Tab• Intro Call• Discovery Call• Technical set-up• Unsell Post Demo Calll• Unsell DemoI• Upsell Scoping Calli• Refresher Session• Sidekick Workshor• Jiminny Onboardine Workshop• Team Launch 2121• Team | aunch 112|€ Chamnion Iaunch 212• Upsell Trial• Discovery Call (existing client)• Internal Handover• Proposal Calli• DM Meeting• Price Negotiation|e Inbound Coll I• Meeting• Discovery Call (unsell)A, AUTODETECT DISABLEDI• Prennine for vour Manager 121 Coaching• Self Goaching Workshon• liminnv lournal I iveAdd PlaybookInspector• Console• Debuaae1.L Network{? Stule Editor(Performancea: Memone StorageFilter URLS11 +[EMAIL]?a=ponxaf/platform-staging&r=6-019e3b46-3a38-7b65-9def-dc3ff [EMAIL]@[EMAIL]@[EMAIL]@r.logr-in.conur.logr-in.co"rloor-ne rlogr-inr.logr-in.a r.logr-inar.loor-ina [EMAIL]@[EMAIL]@[EMAIL]@[EMAIL]@[EMAIL]@r.logr-in.conarloar-inAeloar in [EMAIL]-staging&r=6-019e3b46-3a38-7b65-9def-dc3ff xhtagina&r=6-019e3b46-3a38-7665-9def-dc3tf xhlmrolalto875.99 kB / 2.68 MB transferred# AccessibilitvMediaMon 18 May 16:52:15•Application9994•. X.Disable CacheNo ThrottlingACTIVITY TYPENAMEKick-Off MeetingAPPLIES TOAll ActivitiesAI PROMPT DESCRIPTIONAI SUGGESTIONYou can select up to 5 different calls to help us provide a better suggestion. Make sure toSelect ontioni• Suggest DescrintioStatus |2002002001200| JY-20613...
|
55099
|
NULL
|
NULL
|
NULL
|