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:
parent
b9194b9c7d
commit
6bfb88dede
2 changed files with 70 additions and 7 deletions
|
|
@ -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 },
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue