-
Notifications
You must be signed in to change notification settings - Fork 392
Improve Integration Cards #643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<template> | ||
<div class="flex flex-1 items-center"> | ||
<div | ||
v-if="integration" | ||
class="hidden md:block space-y-1" | ||
> | ||
<UBadge | ||
:label="mentionAsText(integration.data.message)" | ||
color="gray" | ||
size="xs" | ||
class="max-w-[300px] truncate" | ||
/> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { mentionAsText } from '~/lib/utils.js' | ||
|
||
const props = defineProps({ | ||
integration: { | ||
type: Object, | ||
required: true, | ||
}, | ||
form: { | ||
type: Object, | ||
required: true, | ||
} | ||
}) | ||
|
||
const formIntegrationsStore = useFormIntegrationsStore() | ||
let interval = null | ||
|
||
onMounted(() => { | ||
if (!props.integration.data || props.integration.data.length === 0) { | ||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000) | ||
setTimeout(() => { clearInterval(interval) }, 30000) | ||
} | ||
}) | ||
|
||
onBeforeUnmount(() => { | ||
if (interval) { | ||
clearInterval(interval) | ||
} | ||
}) | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
<template> | ||
<div class="flex flex-1 items-center"> | ||
<div | ||
v-if="integration" | ||
class="hidden md:block space-y-1" | ||
> | ||
<UBadge | ||
:label="mentionAsText(integration.data.subject)" | ||
color="gray" | ||
size="xs" | ||
class="max-w-[300px] block truncate" | ||
/> | ||
<div class="flex items-center gap-1"> | ||
<UBadge | ||
:label="firstEmail" | ||
color="white" | ||
size="xs" | ||
class="max-w-[300px] block truncate" | ||
/> | ||
<UBadge | ||
v-if="additionalEmailsCount > 0" | ||
:label="`+${additionalEmailsCount}`" | ||
color="white" | ||
size="xs" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { mentionAsText } from '~/lib/utils.js' | ||
|
||
const props = defineProps({ | ||
integration: { | ||
type: Object, | ||
required: true, | ||
}, | ||
form: { | ||
type: Object, | ||
required: true, | ||
} | ||
}) | ||
|
||
const formIntegrationsStore = useFormIntegrationsStore() | ||
let interval = null | ||
|
||
onMounted(() => { | ||
if (!props.integration.data || props.integration.data.length === 0) { | ||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000) | ||
setTimeout(() => { clearInterval(interval) }, 30000) | ||
} | ||
}) | ||
|
||
onBeforeUnmount(() => { | ||
if (interval) { | ||
clearInterval(interval) | ||
} | ||
}) | ||
|
||
const firstEmail = computed(() => { | ||
const emails = mentionAsText(props.integration.data.send_to).split('\n').filter(Boolean) | ||
return emails[0] || '' | ||
}) | ||
|
||
const additionalEmailsCount = computed(() => { | ||
const emails = mentionAsText(props.integration.data.send_to).split('\n').filter(Boolean) | ||
return Math.max(0, emails.length - 1) | ||
}) | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
<template> | ||
<div class="flex flex-1 items-center"> | ||
<div | ||
v-if="integration" | ||
class="hidden md:block space-y-1" | ||
> | ||
<UBadge | ||
:label="mentionAsText(integration.data.message)" | ||
color="gray" | ||
size="xs" | ||
class="max-w-[300px] block truncate" | ||
/> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script setup> | ||
import { mentionAsText } from '~/lib/utils.js' | ||
|
||
const props = defineProps({ | ||
integration: { | ||
type: Object, | ||
required: true, | ||
}, | ||
form: { | ||
type: Object, | ||
required: true, | ||
} | ||
}) | ||
Comment on lines
+20
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance prop definitions with validation and documentation. The current prop definitions lack detailed type validation and documentation about the expected data structure. Consider enhancing the props: const props = defineProps({
integration: {
type: Object,
required: true,
+ validator(value) {
+ return value && typeof value.data === 'object'
+ },
+ default: () => ({}),
},
form: {
type: Object,
required: true,
+ validator(value) {
+ return value && typeof value.id === 'string'
+ },
+ default: () => ({}),
}
}) Also, consider adding JSDoc comments to document the expected prop structure: /**
* @typedef {Object} Integration
* @property {Object} data - Integration data containing message
* @property {string} data.message - The message to display
*/
/**
* @typedef {Object} Form
* @property {string} id - The form identifier
*/ |
||
|
||
const formIntegrationsStore = useFormIntegrationsStore() | ||
let interval = null | ||
|
||
onMounted(() => { | ||
if (!props.integration.data || props.integration.data.length === 0) { | ||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000) | ||
setTimeout(() => { clearInterval(interval) }, 30000) | ||
} | ||
}) | ||
|
||
onBeforeUnmount(() => { | ||
if (interval) { | ||
clearInterval(interval) | ||
} | ||
}) | ||
Comment on lines
+31
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve polling mechanism and error handling. The current implementation has several potential issues:
Consider these improvements: const formIntegrationsStore = useFormIntegrationsStore()
let interval = null
+const POLL_INTERVAL = 10000 // 10 seconds
+const MAX_RETRIES = 6 // 1 minute total
+let retryCount = 0
+const isLoading = ref(false)
onMounted(() => {
if (!props.integration.data || props.integration.data.length === 0) {
- interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
- setTimeout(() => { clearInterval(interval) }, 30000)
+ interval = setInterval(async () => {
+ try {
+ isLoading.value = true
+ await formIntegrationsStore.fetchFormIntegrations(props.form.id)
+ retryCount++
+ if (retryCount >= MAX_RETRIES) {
+ clearInterval(interval)
+ interval = null
+ }
+ } catch (error) {
+ console.error('Failed to fetch integrations:', error)
+ clearInterval(interval)
+ interval = null
+ } finally {
+ isLoading.value = false
+ }
+ }, POLL_INTERVAL)
}
}) Also add a loading indicator to the template: <UBadge
:label="mentionAsText(integration.data.message)"
color="gray"
size="xs"
class="max-w-[300px] block truncate"
+ :loading="isLoading"
/>
|
||
</script> |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,44 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<template> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div class="flex flex-1 items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
v-if="integration" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class="hidden md:block space-y-1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<UBadge | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
:label="integration.data.webhook_url" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color="gray" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size="xs" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class="max-w-[300px] block truncate" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</template> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<script setup> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const props = defineProps({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
integration: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: Object, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
required: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
form: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
type: Object, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
required: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const formIntegrationsStore = useFormIntegrationsStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let interval = null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onMounted(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!props.integration.data || props.integration.data.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setTimeout(() => { clearInterval(interval) }, 30000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+32
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve polling mechanism robustness The current polling implementation has several potential issues:
Consider implementing a more robust polling mechanism: -let interval = null
+const MAX_RETRIES = 10
+const INITIAL_INTERVAL = 3000
+const MAX_TIMEOUT = 30000
+let retryCount = 0
+let pollingInterval = null
onMounted(() => {
if (!props.integration.data || props.integration.data.length === 0) {
- interval = setInterval(() => formIntegrationsStore.fetchFormIntegrations(props.form.id), 3000)
- setTimeout(() => { clearInterval(interval) }, 30000)
+ const startPolling = async () => {
+ try {
+ await formIntegrationsStore.fetchFormIntegrations(props.form.id)
+ if (formIntegrationsStore.hasData) {
+ clearInterval(pollingInterval)
+ return
+ }
+ retryCount++
+ if (retryCount >= MAX_RETRIES) {
+ clearInterval(pollingInterval)
+ }
+ } catch (error) {
+ console.error('Failed to fetch integrations:', error)
+ clearInterval(pollingInterval)
+ }
+ }
+ pollingInterval = setInterval(startPolling, INITIAL_INTERVAL)
+ setTimeout(() => clearInterval(pollingInterval), MAX_TIMEOUT)
}
}) 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onBeforeUnmount(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (interval) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
clearInterval(interval) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve polling mechanism robustness
The current polling implementation has several potential issues:
Consider these improvements:
📝 Committable suggestion