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
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,20 @@ const enabled = computed<boolean>({
});

const getLabel = (field: string) => {
const label = field
const is12MonthPresent = field.includes('12Month');
let sentence = field
.replace('attributes.', '')
.replace('12Month', '')
.replace('_', ' ')
.replace(/([A-Z])/g, ' $1');
return label.at(0).toUpperCase() + label.substring(1).toLowerCase();
.replace(/([A-Z])/g, ' $1')
.trim();

if (is12MonthPresent) {
sentence = sentence
.replace(/^/, 'Annual ');
}

return sentence.charAt(0).toUpperCase() + sentence.slice(1).toLowerCase();
};
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import {
HubspotAutomationTrigger,
} from '@/modules/automation/config/automation-types/hubspot/types/HubspotAutomationTrigger';
import { HubspotEntity } from '@/integrations/hubspot/types/HubspotEntity';
import AutomationsHubspotPaywall from './hubspot-paywall.vue';
import AutomationsHubspotTrigger from './hubspot-trigger.vue';
import annualEmployeeChurnRate from '@/modules/organization/config/filters/annualEmployeeChurnRate/config';
import annualEmployeeGrowthRate from '@/modules/organization/config/filters/annualEmployeeGrowthRate/config';
import employeeCount from '@/modules/organization/config/filters/employeeCount/config';
import organizationTags from '@/modules/organization/config/filters/tags/config';
import AutomationsHubspotAction from './hubspot-action.vue';
import AutomationsHubspotTrigger from './hubspot-trigger.vue';
import AutomationsHubspotPaywall from './hubspot-paywall.vue';

export const hubspotMemberFilters: Record<string, FilterConfig> = {
noOfActivities,
Expand All @@ -31,6 +35,10 @@ export const hubspotOrganizationFilters: Record<string, FilterConfig> = {
headcount,
industry,
annualRevenue,
annualEmployeeChurnRate,
annualEmployeeGrowthRate,
employeeCount,
organizationTags,
};

export const hubspot: AutomationTypeConfig = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,140 @@
</template>
</el-table-column>

<!-- Employee Churn Rate -->
<el-table-column
label="Ann. Employee Churn Rate"
width="220"
>
<template #default="scope">
<router-link
:to="{
name: 'organizationView',
params: { id: scope.row.id },
}"
class="block"
>
<div
class="text-sm h-full flex items-center"
>
<span v-if="scope.row.employeeChurnRate?.['12_month']" class="text-gray-900">
{{
employeeChurnRate.valueParser(scope.row.employeeChurnRate['12_month'])
}}
</span>
<span v-else class="text-gray-500">-</span>
</div>
</router-link>
</template>
</el-table-column>

<!-- Employee Growth Rate -->
<el-table-column
label="Ann. Employee Growth Rate"
width="230"
>
<template #default="scope">
<router-link
:to="{
name: 'organizationView',
params: { id: scope.row.id },
}"
class="block"
>
<div
class="text-sm h-full flex items-center"
>
<span v-if="scope.row.employeeGrowthRate?.['12_month']" class="text-gray-900">
{{
employeeGrowthRate.valueParser(scope.row.employeeGrowthRate['12_month'])
}}
</span>
<span v-else class="text-gray-500">-</span>
</div>
</router-link>
</template>
</el-table-column>

<!-- Employee Count -->
<el-table-column
label="Employee Count"
width="150"
>
<template #default="scope">
<router-link
:to="{
name: 'organizationView',
params: { id: scope.row.id },
}"
class="block"
>
<div
class="text-sm h-full flex items-center"
>
<span v-if="scope.row.employees" class="text-gray-900">
{{
scope.row.employees
}}
</span>
<span v-else class="text-gray-500">-</span>
</div>
</router-link>
</template>
</el-table-column>

<!-- Inferred Revenue -->
<el-table-column
label="Annual Revenue"
width="150"
>
<template #default="scope">
<router-link
:to="{
name: 'organizationView',
params: { id: scope.row.id },
}"
class="block"
>
<div
class="text-sm h-full flex items-center"
>
<span v-if="scope.row.revenueRange" class="text-gray-900">
{{
revenueRange.displayValue(scope.row.revenueRange)
}}
</span>
<span v-else class="text-gray-500">-</span>
</div>
</router-link>
</template>
</el-table-column>

<!-- Tags -->
<el-table-column
label="Tags"
:width="tagsColumnWidth"
>
<template #default="scope">
<router-link
:to="{
name: 'organizationView',
params: { id: scope.row.id },
}"
class="block"
>
<app-tag-list
v-if="scope.row.tags?.length"
:member="{
...scope.row,
tags: scope.row.tags.map((t) => ({ id: t, name: t })),
}"
:editable="false"
/>
<span v-else class="text-gray-500">-</span>
</router-link>
</template>
</el-table-column>

<!-- Actions -->
<el-table-column fixed="right">
<template #default="scope">
Expand Down Expand Up @@ -532,7 +666,6 @@
<script setup>
import {
computed,
defineProps,
ref,
watch,
onUnmounted,
Expand All @@ -544,6 +677,10 @@ import { withHttp, toSentenceCase } from '@/utils/string';
import { useOrganizationStore } from '@/modules/organization/store/pinia';
import { storeToRefs } from 'pinia';
import AppOrganizationMergeDialog from '@/modules/organization/components/organization-merge-dialog.vue';
import employeeChurnRate from '@/modules/organization/config/enrichment/employeeChurnRate';
import employeeGrowthRate from '@/modules/organization/config/enrichment/employeeGrowthRate';
import revenueRange from '@/modules/organization/config/enrichment/revenueRange';
import AppTagList from '@/modules/tag/components/tag-list.vue';
import AppOrganizationIdentities from '../organization-identities.vue';
import AppOrganizationListToolbar from './organization-list-toolbar.vue';
import AppOrganizationName from '../organization-name.vue';
Expand Down Expand Up @@ -607,6 +744,24 @@ const showBottomPagination = computed(() => (
));
const isLoading = computed(() => props.isPageLoading);

const tagsColumnWidth = computed(() => {
let maxTabWidth = 0;

organizations.value.forEach((row) => {
if (row.tags) {
const tabWidth = row.tags
.map((tag) => tag.length * 20)
.reduce((a, b) => a + b, 0);

if (tabWidth > maxTabWidth) {
maxTabWidth = tabWidth;
}
}
});

return Math.min(maxTabWidth + 100, 500);
});

document.onmouseup = () => {
// As soon as mouse is released, set scrollbar visibility
// according to wether the mouse is hovering the table or not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,11 @@
>
<span
v-if="parsedValue(value) !== null && parsedValue(value) !== ''"
class="font-medium mr-1"
:class="{
'text-gray-500': !!nestedKeyParser,
}"
>{{ keyParser(key) }}{{ !!nestedKeyParser ? '' : ':' }}</span>
<div v-if="nestedKeyParser">
<div
v-for="[nestedKey, nestedValue] of Object.entries(value)"
:key="nestedKey"
class="last:mb-2"
>
<span class="font-medium mr-1">{{ nestedKeyParser(nestedKey) }}:</span>
<span>{{ parsedValue(nestedValue) }}</span>
</div>
</div>
<span v-else>{{ parsedValue(value) }}</span>
class="flex flex-grow items-center justify-between"
>
<span class="font-medium mr-1 text-gray-900">{{ keyParser(key) }}</span>
<span class="text-gray-600">{{ parsedValue(value) }}</span>
</span>
</div>
</div>
<div
Expand All @@ -49,10 +38,6 @@ const props = defineProps({
type: Function,
required: true,
},
nestedKeyParser: {
type: Function,
default: null,
},
valueParser: {
type: Function,
default: null,
Expand All @@ -73,10 +58,10 @@ const parsedAttributeValue = computed(() => {
return props.attributeValue;
});

const displayShowMore = computed(() => Object.entries(parsedAttributeValue.value).length > 10);
const displayShowMore = computed(() => Object.entries(parsedAttributeValue.value).length > 5);
const valueSegment = computed(() => {
if (displayShowMore.value && !showMore.value) {
return Object.entries(parsedAttributeValue.value).slice(0, 10);
return Object.entries(parsedAttributeValue.value).slice(0, 5);
}

return Object.entries(parsedAttributeValue.value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
v-else-if="attribute.component && attribute.type === AttributeType.JSON"
:attribute-value="organization[attribute.name]"
:key-parser="attribute.keyParser"
:nested-key-parser="attribute.nestedKeyParser"
:value-parser="attribute.valueParser"
:filter-value="attribute.filterValue"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
NumberFilterConfig,
NumberFilterOptions,
NumberFilterValue,
} from '@/shared/modules/filters/types/filterTypes/NumberFilterConfig';
import { FilterConfigType } from '@/shared/modules/filters/types/FilterConfig';
import { itemLabelRendererByType } from '@/shared/modules/filters/config/itemLabelRendererByType';
import { apiFilterRendererByType } from '@/shared/modules/filters/config/apiFilterRendererByType';
import {
decimal, required,
} from '@vuelidate/validators';

const valueParser = (value) => value / 100;

const annualEmployeeChurnRate: NumberFilterConfig = {
id: 'annualEmployeeChurnRate',
label: 'Annual Employee Churn Rate',
iconClass: 'ri-arrow-down-circle-line',
type: FilterConfigType.NUMBER,
options: {
suffix: '%',
validators: {
required,
decimal,
},
},
itemLabelRenderer(value: NumberFilterValue, options: NumberFilterOptions): string {
return itemLabelRendererByType[FilterConfigType.NUMBER]('Annual Employee Churn Rate', value, options);
},
apiFilterRenderer(value: NumberFilterValue): any[] {
return apiFilterRendererByType[FilterConfigType.NUMBER]('employeeChurnRate12Month', value, valueParser);
},
};

export default annualEmployeeChurnRate;
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
NumberFilterConfig,
NumberFilterOptions,
NumberFilterValue,
} from '@/shared/modules/filters/types/filterTypes/NumberFilterConfig';
import { FilterConfigType } from '@/shared/modules/filters/types/FilterConfig';
import { itemLabelRendererByType } from '@/shared/modules/filters/config/itemLabelRendererByType';
import { apiFilterRendererByType } from '@/shared/modules/filters/config/apiFilterRendererByType';
import {
decimal, required,
} from '@vuelidate/validators';

const valueParser = (value) => value / 100;

const annualEmployeeGrowthRate: NumberFilterConfig = {
id: 'annualEmployeeGrowthRate',
label: 'Annual Employee Growth Rate',
iconClass: 'ri-arrow-up-circle-line',
type: FilterConfigType.NUMBER,
options: {
suffix: '%',
validators: {
required,
decimal,
},
},
itemLabelRenderer(value: NumberFilterValue, options: NumberFilterOptions): string {
return itemLabelRendererByType[FilterConfigType.NUMBER]('Annual Employee Growth Rate', value, options);
},
apiFilterRenderer(value: NumberFilterValue): any[] {
return apiFilterRendererByType[FilterConfigType.NUMBER]('employeeGrowthRate12Month', value, valueParser);
},
};

export default annualEmployeeGrowthRate;
Loading