Skip to content

Commit ca16c6e

Browse files
feat: show error information on failed flows
1 parent cb31087 commit ca16c6e

12 files changed

Lines changed: 319 additions & 71 deletions

File tree

src/Entity/FlowState/FlowStateDefinition.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected function defineFields(): FieldCollection
4444
(new IdField('id', 'id'))->addFlags(new PrimaryKey(), new Required()),
4545
(new FkField('flow_id', 'flowId', FlowDefinition::class))->addFlags(new Required()),
4646
(new StringField('state', 'state'))->addFlags(new Required()),
47-
new LongTextField('error', 'error'),
47+
new JsonField('error', 'error'),
4848
new JsonField('data', 'data'),
4949
new FkField('user_id', 'userId', UserDefinition::class),
5050
new FkField('integration_id', 'integrationId', IntegrationDefinition::class),

src/Entity/FlowState/FlowStateEntity.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class FlowStateEntity extends Entity
1919

2020
protected string $state;
2121

22-
protected ?string $error = null;
22+
protected ?array $error = null;
2323

2424
protected ?array $data = null;
2525

@@ -57,12 +57,12 @@ public function setState(string $state): void
5757
$this->state = $state;
5858
}
5959

60-
public function getError(): ?string
60+
public function getError(): ?array
6161
{
6262
return $this->error;
6363
}
6464

65-
public function setError(?string $error): void
65+
public function setError(?array $error): void
6666
{
6767
$this->error = $error;
6868
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Frosh\FlowBuilder\Migration;
6+
7+
use Doctrine\DBAL\Connection;
8+
use Shopware\Core\Framework\Migration\MigrationStep;
9+
10+
class Migration1775132753ChangeExceptionColumnToJson extends MigrationStep
11+
{
12+
public function getCreationTimestamp(): int
13+
{
14+
return 1775132753;
15+
}
16+
17+
public function update(Connection $connection): void
18+
{
19+
$connection->executeStatement(
20+
'ALTER TABLE `frosh_flow_state` DROP COLUMN `error`;
21+
ALTER TABLE `frosh_flow_state` ADD COLUMN `error` JSON NULL'
22+
);
23+
}
24+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<sw-modal
2+
:title="$tc('frosh-flow-builder.dataModal.title')"
3+
@modal-close="onModalChange"
4+
>
5+
<template #body>
6+
<sw-container style="padding: 20px 30px;">
7+
<sw-container
8+
columns="1fr 1fr 1fr"
9+
gap="0px 15px"
10+
class="frosh-flow-data-modal__metadata"
11+
>
12+
<sw-description-list>
13+
<dt>{{ $tc('frosh-flow-builder.history.columns.executedAt') }}</dt>
14+
<dd>{{ executedAt }}</dd>
15+
</sw-description-list>
16+
<sw-description-list>
17+
<dt>{{ $tc('frosh-flow-builder.history.columns.status') }}</dt>
18+
<dd>
19+
<div style="display: flex; align-items: center; gap: 8px;">
20+
<sw-color-badge
21+
:color="stateColor"
22+
rounded
23+
/>
24+
{{ $tc('frosh-flow-builder.history.state.' + flowHistoryEntry.state) }}
25+
</div>
26+
</dd>
27+
</sw-description-list>
28+
<sw-description-list>
29+
<dt>{{ $tc('frosh-flow-builder.history.columns.triggeredBy') }}</dt>
30+
<dd>
31+
<router-link
32+
v-if="flowHistoryEntry.customer"
33+
:to="{ name: 'sw.customer.detail', params: { id: flowHistoryEntry.customerId } }"
34+
style="display: inline-flex; align-items: center; gap: 6px;"
35+
>
36+
<sw-icon name="regular-users" size="16"/>
37+
{{ flowHistoryEntry.customer.firstName }} {{ flowHistoryEntry.customer.lastName }} ({{ flowHistoryEntry.customer.customerNumber }})
38+
</router-link>
39+
<router-link
40+
v-else-if="flowHistoryEntry.user"
41+
:to="{ name: 'sw.users.permissions.user.detail', params: { id: flowHistoryEntry.userId } }"
42+
style="display: inline-flex; align-items: center; gap: 6px;"
43+
>
44+
<sw-icon name="regular-user" size="16"/>
45+
{{ flowHistoryEntry.user.username }}
46+
</router-link>
47+
<router-link
48+
v-else-if="flowHistoryEntry.integration"
49+
:to="{ name: 'sw.integration.index' }"
50+
style="display: inline-flex; align-items: center; gap: 6px;"
51+
>
52+
<sw-icon name="regular-plug" size="16"/>
53+
{{ flowHistoryEntry.integration.label }}
54+
</router-link>
55+
<template v-else>-</template>
56+
</dd>
57+
</sw-description-list>
58+
</sw-container>
59+
60+
<mt-textarea
61+
:model-value="flowData"
62+
:label="$tc('frosh-flow-builder.dataModal.payloadLabel')"
63+
:disabled="true"
64+
/>
65+
</sw-container>
66+
67+
<sw-container
68+
v-if="flowHistoryEntry.error"
69+
style="border-top: 1px solid #d1d9e0; padding: 20px 30px;"
70+
>
71+
<sw-container
72+
columns="1fr 1fr"
73+
gap="0px 15px"
74+
class="frosh-flow-data-modal__metadata"
75+
>
76+
<sw-description-list>
77+
<dt>{{ $tc('frosh-flow-builder.dataModal.errorType') }}</dt>
78+
<dd>{{ flowHistoryEntry.error.type }}</dd>
79+
</sw-description-list>
80+
<sw-description-list>
81+
<dt>{{ $tc('frosh-flow-builder.dataModal.errorLine') }}</dt>
82+
<dd>{{ flowHistoryEntry.error.line }}</dd>
83+
</sw-description-list>
84+
</sw-container>
85+
86+
<sw-description-list class="frosh-flow-data-modal__error-file">
87+
<dt>{{ $tc('frosh-flow-builder.dataModal.errorFile') }}</dt>
88+
<dd>{{ flowHistoryEntry.error.file }}</dd>
89+
</sw-description-list>
90+
91+
<mt-textarea
92+
:model-value="flowHistoryEntry.error.message"
93+
:label="$tc('frosh-flow-builder.dataModal.errorMessage')"
94+
:disabled="true"
95+
/>
96+
</sw-container>
97+
</template>
98+
</sw-modal>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.frosh-flow-data-modal__metadata {
2+
margin-bottom: 20px;
3+
4+
.sw-description-list dt {
5+
padding: 8px 4px;
6+
}
7+
8+
.sw-description-list dd {
9+
padding: 2px 4px;
10+
}
11+
}
12+
13+
.sw-description-list.frosh-flow-data-modal__error-file {
14+
15+
dt {
16+
padding: 8px 4px;
17+
}
18+
19+
dd {
20+
padding: 2px 4px;
21+
}
22+
23+
margin-bottom: 20px;
24+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import template from './frosh-flow-data-modal.html.twig'
2+
import './frosh-flow-data-modal.scss'
3+
4+
const {Component} = Shopware
5+
6+
Component.register('frosh-flow-data-modal', {
7+
template,
8+
emits: ['modal-close'],
9+
props: {
10+
flowHistoryEntry: {
11+
required: true,
12+
type: Object
13+
}
14+
},
15+
methods: {
16+
onModalChange() {
17+
this.$emit('modal-close');
18+
},
19+
},
20+
computed: {
21+
flowData() {
22+
const data = this.flowHistoryEntry.data
23+
return data ? JSON.stringify(data, null, 2) : ''
24+
},
25+
dateFilter() {
26+
return Shopware.Filter.getByName('date');
27+
},
28+
executedAt() {
29+
return this.dateFilter(this.flowHistoryEntry.createdAt, { hour: '2-digit', minute: '2-digit' });
30+
},
31+
stateColor() {
32+
const colorMap = {
33+
success: '#37d046',
34+
error: '#de294c',
35+
};
36+
37+
return colorMap[this.flowHistoryEntry.state] || '#d1d9e0';
38+
},
39+
}
40+
})
Lines changed: 71 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,71 @@
1-
<mt-card
2-
:is-loading="isLoading"
3-
:title="$tc('frosh-flow-builder.history.cardTitle')"
4-
position-identifier="sw-flow-frosh-history-list"
5-
>
6-
<template #grid>
7-
<sw-one-to-many-grid
8-
v-if="flow"
9-
:collection="flow.extensions.froshFlowStates"
10-
:columns="columns"
11-
:full-page="false"
12-
:local-mode="false"
13-
:allow-inline-edit="false"
14-
:allow-delete="false"
15-
:selectable="false"
16-
>
17-
<template #column-createdAt="{ item }">
18-
{{ dateFilter(item.createdAt, { hour: '2-digit', minute: '2-digit' }) }}
19-
</template>
20-
<template #column-state="{ item }">
21-
<div style="display: flex; align-items: center; gap: 8px;">
22-
<sw-color-badge
23-
:color="getStateColor(item.state)"
24-
rounded
25-
/>
26-
{{ $tc('frosh-flow-builder.history.state.' + item.state) }}
27-
</div>
28-
</template>
29-
<template #column-triggeredBy="{ item }">
30-
<router-link
31-
v-if="item.customer"
32-
:to="{ name: 'sw.customer.detail', params: { id: item.customerId } }"
33-
style="display: inline-flex; align-items: center; gap: 6px;"
34-
>
35-
<sw-icon name="regular-users" size="16" />
36-
{{ item.customer.firstName }} {{ item.customer.lastName }} ({{ item.customer.customerNumber }})
37-
</router-link>
38-
<router-link
39-
v-else-if="item.user"
40-
:to="{ name: 'sw.users.permissions.user.detail', params: { id: item.userId } }"
41-
style="display: inline-flex; align-items: center; gap: 6px;"
42-
>
43-
<sw-icon name="regular-user" size="16" />
44-
{{ item.user.username }}
45-
</router-link>
46-
<router-link
47-
v-else-if="item.integration"
48-
:to="{ name: 'sw.integration.index' }"
49-
style="display: inline-flex; align-items: center; gap: 6px;"
50-
>
51-
<sw-icon name="regular-plug" size="16" />
52-
{{ item.integration.label }}
53-
</router-link>
54-
</template>
55-
</sw-one-to-many-grid>
56-
</template>
57-
</mt-card>
1+
<div>
2+
<mt-card
3+
:is-loading="isLoading"
4+
:title="$tc('frosh-flow-builder.history.cardTitle')"
5+
position-identifier="sw-flow-frosh-history-list"
6+
>
7+
<template #grid>
8+
<sw-one-to-many-grid
9+
v-if="flow"
10+
:collection="flow.extensions.froshFlowStates"
11+
:columns="columns"
12+
:full-page="false"
13+
:local-mode="false"
14+
:allow-inline-edit="false"
15+
:allow-delete="false"
16+
:selectable="false"
17+
>
18+
<template #column-createdAt="{ item }">
19+
{{ dateFilter(item.createdAt, { hour: '2-digit', minute: '2-digit' }) }}
20+
</template>
21+
<template #column-state="{ item }">
22+
<div style="display: flex; align-items: center; gap: 8px;">
23+
<sw-color-badge
24+
:color="getStateColor(item.state)"
25+
rounded
26+
/>
27+
{{ $tc('frosh-flow-builder.history.state.' + item.state) }}
28+
</div>
29+
</template>
30+
<template #column-triggeredBy="{ item }">
31+
<router-link
32+
v-if="item.customer"
33+
:to="{ name: 'sw.customer.detail', params: { id: item.customerId } }"
34+
style="display: inline-flex; align-items: center; gap: 6px;"
35+
>
36+
<sw-icon name="regular-users" size="16"/>
37+
{{ item.customer.firstName }} {{ item.customer.lastName }} ({{ item.customer.customerNumber }})
38+
</router-link>
39+
<router-link
40+
v-else-if="item.user"
41+
:to="{ name: 'sw.users.permissions.user.detail', params: { id: item.userId } }"
42+
style="display: inline-flex; align-items: center; gap: 6px;"
43+
>
44+
<sw-icon name="regular-user" size="16"/>
45+
{{ item.user.username }}
46+
</router-link>
47+
<router-link
48+
v-else-if="item.integration"
49+
:to="{ name: 'sw.integration.index' }"
50+
style="display: inline-flex; align-items: center; gap: 6px;"
51+
>
52+
<sw-icon name="regular-plug" size="16"/>
53+
{{ item.integration.label }}
54+
</router-link>
55+
</template>
56+
<template #actions="{ item }">
57+
<sw-context-menu-item
58+
@click="openDetailsModal(item)"
59+
>
60+
{{ $tc('frosh-flow-builder.history.actions.showDetails') }}
61+
</sw-context-menu-item>
62+
</template>
63+
</sw-one-to-many-grid>
64+
</template>
65+
</mt-card>
66+
<frosh-flow-data-modal
67+
v-if="modalEntry"
68+
:flowHistoryEntry="modalEntry"
69+
@modal-close="onCloseModal"
70+
/>
71+
</div>

src/Resources/app/administration/src/extension/sw-flow/component/frosh-flow-history/index.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ Component.register('frosh-flow-history', {
1212
default: false,
1313
},
1414
},
15+
data: () => {
16+
return {
17+
modalEntry: null
18+
}
19+
},
1520
computed: {
1621
columns() {
1722
return [
@@ -44,5 +49,15 @@ Component.register('frosh-flow-history', {
4449

4550
return colorMap[state] || '#d1d9e0';
4651
},
52+
53+
openDetailsModal(item) {
54+
this.modalEntry = item
55+
},
56+
onCloseModal(){
57+
this.modalEntry = null
58+
}
4759
},
60+
created() {
61+
console.log(this.flow.extensions.froshFlowStates)
62+
}
4863
})

src/Resources/app/administration/src/extension/sw-flow/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import './component/frosh-flow-history'
2+
import './component/frosh-flow-data-modal'
23
import './page/sw-flow-detail'
34

45
Shopware.Module.register('frosh-flow-tab-history', {

0 commit comments

Comments
 (0)