Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/.env.dist.local
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ CROWD_SENDGRID_TEMPLATE_EMAIL_ADDRESS_VERIFICATION=
CROWD_SENDGRID_TEMPLATE_INVITATION=
CROWD_SENDGRID_TEMPLATE_PASSWORD_RESET=
CROWD_SENDGRID_TEMPLATE_WEEKLY_ANALYTICS=
CROWD_SENDGRID_TEMPLATE_INTEGRATION_DONE=
CROWD_SENDGRID_WEEKLY_ANALYTICS_UNSUBSCRIBE_GROUP_ID=

# Stripe settings
Expand Down
1 change: 1 addition & 0 deletions backend/config/custom-environment-variables.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"templateInvitation": "CROWD_SENDGRID_TEMPLATE_INVITATION",
"templatePasswordReset": "CROWD_SENDGRID_TEMPLATE_PASSWORD_RESET",
"templateWeeklyAnalytics": "CROWD_SENDGRID_TEMPLATE_WEEKLY_ANALYTICS",
"templateIntegrationDone": "CROWD_SENDGRID_TEMPLATE_INTEGRATION_DONE",
"weeklyAnalyticsUnsubscribeGroupId": "CROWD_SENDGRID_WEEKLY_ANALYTICS_UNSUBSCRIBE_GROUP_ID"
},
"plans": {
Expand Down
1 change: 1 addition & 0 deletions backend/src/config/configTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export interface SendgridConfiguration {
templateInvitation: string
templatePasswordReset: string
templateWeeklyAnalytics: string
templateIntegrationDone: string
weeklyAnalyticsUnsubscribeGroupId: string
}

Expand Down
1 change: 1 addition & 0 deletions backend/src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export const SENDGRID_CONFIG: SendgridConfiguration = KUBE_MODE
templateInvitation: process.env.SENDGRID_TEMPLATE_INVITATION,
templatePasswordReset: process.env.SENDGRID_TEMPLATE_PASSWORD_RESET,
templateWeeklyAnalytics: process.env.SENDGRID_TEMPLATE_WEEKLY_ANALYTICS,
templateIntegrationDone: process.env.SENDGRID_TEMPLATE_INTEGRATION_DONE,
}

export const NETLIFY_CONFIG: NetlifyConfiguration = KUBE_MODE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE public.integrations DROP COLUMN "emailSentAt";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE public.integrations ADD "emailSentAt" TIMESTAMP NULL;
3 changes: 3 additions & 0 deletions backend/src/database/models/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default (sequelize) => {
len: [0, 255],
},
},
emailSentAt: {
type: DataTypes.DATE,
},
},
{
indexes: [
Expand Down
2 changes: 2 additions & 0 deletions backend/src/database/repositories/integrationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class IntegrationRepository {
'settings',
'integrationIdentifier',
'importHash',
'emailSentAt',
]),

tenantId: tenant.id,
Expand Down Expand Up @@ -78,6 +79,7 @@ class IntegrationRepository {
'settings',
'integrationIdentifier',
'importHash',
'emailSentAt',
]),

updatedById: currentUser.id,
Expand Down
13 changes: 13 additions & 0 deletions backend/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,19 @@ const en = {
unique: {},
},
},
integration: {
name: {
github: 'GitHub',
linkedin: 'LinkedIn',
twitter: 'Twitter',
devto: 'DEV',
stackoverflow: 'Stack Overflow',
reddit: 'Reddit',
discord: 'Discord',
slack: 'Slack',
hackernews: 'Hacker News',
},
},
automation: {
errors: {
planLimitExceeded: 'You have exceeded # of automations you can have in your plan.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import { TwitterReachIntegrationService } from './integrations/twitterReachInteg
import { SlackIntegrationService } from './integrations/slackIntegrationService'
import { GithubIntegrationService } from './integrations/githubIntegrationService'
import { LoggingBase } from '../../../services/loggingBase'
import { API_CONFIG } from '../../../config'
import EmailSender from '../../../services/emailSender'
import UserRepository from '../../../database/repositories/userRepository'
import { i18n } from '../../../i18n'

const MAX_STREAM_RETRIES = 5

Expand Down Expand Up @@ -452,10 +456,22 @@ export class IntegrationProcessor extends LoggingBase {
logger.error(err, 'Error while processing integration!')
setError = req.onboarding
} finally {
let emailSentAt
if (!setError && !integration.emailSentAt) {
const tenantUsers = await UserRepository.findAllUsersOfTenant(integration.tenantId)
emailSentAt = new Date()
for (const user of tenantUsers) {
await new EmailSender(EmailSender.TEMPLATES.INTEGRATION_DONE, {
integrationName: i18n('en', `entities.integration.name.${integration.platform}`),
link: API_CONFIG.frontendUrl,
}).sendTo(user.email)
}
}
await IntegrationRepository.update(
integration.id,
{
status: setError ? 'error' : 'done',
emailSentAt,
settings: stepContext.integration.settings,
refreshToken: stepContext.integration.refreshToken,
token: stepContext.integration.token,
Expand Down
1 change: 1 addition & 0 deletions backend/src/services/emailSender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default class EmailSender extends LoggingBase {
INVITATION: SENDGRID_CONFIG.templateInvitation,
PASSWORD_RESET: SENDGRID_CONFIG.templatePasswordReset,
WEEKLY_ANALYTICS: SENDGRID_CONFIG.templateWeeklyAnalytics,
INTEGRATION_DONE: SENDGRID_CONFIG.templateIntegrationDone,
}
}

Expand Down
63 changes: 56 additions & 7 deletions frontend/src/modules/layout/components/layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</div>
</banner>
<banner
v-if="shouldShowIntegrationsAlert"
v-if="shouldShowIntegrationsErrorAlert"
variant="alert"
>
<div
Expand All @@ -39,6 +39,33 @@
</router-link>
</div>
</banner>

<banner
v-if="shouldShowIntegrationsInProgressAlert"
variant="info"
>
<div
class="flex items-center justify-center grow text-sm"
>
<div
v-loading="true"
class="w-4 h-4 mr-2"
></div>
<span class="font-semibold mr-1"
>{{
integrationsInProgressToString
}}
integration{{
integrationsInProgress.length > 1
? 's are'
: ' is'
}}
getting set up.</span
>
Sit back and relax. We will send you an email
when it’s done.
</div>
</banner>
<banner
v-if="shouldShowTenantCreatingAlert"
variant="info"
Expand All @@ -50,9 +77,11 @@
v-loading="true"
class="w-4 h-4 mr-2"
></div>
Finishing your workspace setup. The data might
take a few minutes until it is completely
loaded.
<span class="font-semibold"
>Finishing your workspace setup.</span
>
The data might take a few minutes until it is
completely loaded.
</div>
</banner>
<banner
Expand Down Expand Up @@ -133,7 +162,26 @@ export default {
integrationsInProgress: 'integration/inProgress',
integrationsWithErrors: 'integration/withErrors'
}),
shouldShowIntegrationsAlert() {
integrationsInProgressToString() {
const arr = this.integrationsInProgress.map(
(i) => i.name
)
if (arr.length === 1) {
return arr[0]
} else if (arr.length === 2) {
return `${arr[0]} and ${arr[1]}`
} else {
return (
arr.slice(0, arr.length - 1).join(', ') +
', and ' +
arr.slice(-1)
)
}
},
shouldShowIntegrationsInProgressAlert() {
return this.integrationsInProgress.length > 0
},
shouldShowIntegrationsErrorAlert() {
return (
this.integrationsWithErrors.length > 0 &&
this.$route.name !== 'integration'
Expand All @@ -154,14 +202,15 @@ export default {
moment().diff(
moment(this.currentTenant.createdAt),
'minutes'
) <= 10
) <= 2
)
},
computedBannerWrapperClass() {
return {
'pt-16':
this.shouldShowSampleDataAlert ||
this.shouldShowIntegrationsAlert ||
this.shouldShowIntegrationsErrorAlert ||
this.shouldShowIntegrationsInProgressAlert ||
this.shouldShowTenantCreatingAlert ||
this.shouldShowPMFSurveyAlert
}
Expand Down