Fix Generate node clamping image count to 0 for Pinterest.

Empty-account mount was clamping target_slide_count to 0 and never raising it when a media-required account was selected, so Pinterest showed a false requires-media error after picking a board.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Paulo Castellano 2026-07-24 23:26:32 -03:00
parent b9194b9c7d
commit 6bfb88dede
2 changed files with 70 additions and 7 deletions

View file

@ -232,11 +232,24 @@ const imageCountCap = computed(() =>
),
);
// Single picker: 0 = no image (text-only), 1 = single image, 2+ = carousel.
const imageCountOptions = computed(() =>
Array.from({ length: imageCountCap.value + 1 }, (_, i) => i),
// Floor at 1 when any selected account requires media (Pinterest pin, IG feed,
// etc.) otherwise the empty-accounts clamp to 0 sticks after selecting them
// and surfaces a false "add an image" compliance error.
const minImageCount = computed(() =>
local.value.accounts.some((a) => getMediaRulesForContentType(a.content_type).requiresMedia)
? 1
: 0,
);
// Single picker: 0 = no image (text-only), 1 = single image, 2+ = carousel.
// Option 0 is omitted when a media-required account is selected.
const imageCountOptions = computed(() => {
const min = Math.min(minImageCount.value, imageCountCap.value);
const max = imageCountCap.value;
return Array.from({ length: Math.max(0, max - min + 1) }, (_, i) => i + min);
});
const intendedImageCount = computed(() => local.value.target_slide_count);
const syntheticImages = (count: number): MediaItem[] =>
@ -254,14 +267,23 @@ const accountIssue = (accountId: string): string | null => {
return account ? getPlatformMetaIssue(account.platform, entry.meta) : null;
};
// Clamp the chosen count to what the selected accounts actually allow runs on
// mount too so legacy/over-cap values (or text-only accounts 0) self-correct.
// Clamp the chosen count into [min, cap] for the current selection. Skip while
// no accounts are selected so the default of 1 is preserved until the user
// picks a destination (avoids clamp-to-0 select Pinterest stuck at 0).
watch(
imageCountCap,
(cap) => {
[imageCountCap, minImageCount, () => local.value.accounts.length],
([cap, min, accountCount]) => {
if (accountCount === 0) {
return;
}
if (local.value.target_slide_count > cap) {
local.value.target_slide_count = cap;
}
if (local.value.target_slide_count < min) {
local.value.target_slide_count = Math.min(min, cap);
}
},
{ immediate: true },
);

View file

@ -58,6 +58,47 @@
expect($automation->fresh()->nodes)->toHaveCount(2);
});
it('rejects a generate node that targets Pinterest with zero images', function () {
$automation = Automation::factory()->for($this->workspace)->create();
$this->actingAs($this->user)
->putJson(route('app.automations.update', $automation->id), [
'nodes' => [
['id' => 'n1', 'type' => 'trigger', 'position' => ['x' => 0, 'y' => 0], 'data' => ['trigger_type' => 'schedule', 'cron' => '0 9 * * *']],
['id' => 'n2', 'type' => 'generate', 'position' => ['x' => 1, 'y' => 0], 'data' => [
'accounts' => [['social_account_id' => 'acc-1', 'content_type' => 'pinterest_pin', 'meta' => ['board_id' => 'board-1']]],
'prompt_template' => 'hi',
'target_slide_count' => 0,
]],
],
'connections' => [['id' => 'e1', 'source' => 'n1', 'target' => 'n2']],
])
->assertStatus(422)
->assertJsonValidationErrors(['nodes.1.data.accounts']);
});
it('allows saving a Pinterest pin generate node with one image', function () {
$automation = Automation::factory()->for($this->workspace)->create();
$this->actingAs($this->user)
->put(route('app.automations.update', $automation->id), [
'nodes' => [
['id' => 'n1', 'type' => 'trigger', 'position' => ['x' => 0, 'y' => 0], 'data' => ['trigger_type' => 'schedule', 'cron' => '0 9 * * *']],
['id' => 'n2', 'type' => 'generate', 'position' => ['x' => 1, 'y' => 0], 'data' => [
'accounts' => [['social_account_id' => 'acc-1', 'content_type' => 'pinterest_pin', 'meta' => ['board_id' => 'board-1']]],
'prompt_template' => 'hi',
'target_slide_count' => 1,
'style' => 'tweet_card',
]],
],
'connections' => [['id' => 'e1', 'source' => 'n1', 'target' => 'n2']],
])
->assertRedirect()
->assertSessionHasNoErrors();
expect($automation->fresh()->nodes)->toHaveCount(2);
});
it('persists the brand toggles on the generate node', function () {
$automation = Automation::factory()->for($this->workspace)->create();