Skip to content

Commit

Permalink
Merge branch 'crowd-linux' into improvement/same-work-experience
Browse files Browse the repository at this point in the history
  • Loading branch information
gaspergrom committed Jul 31, 2024
2 parents 230715f + 851066f commit f33aaea
Show file tree
Hide file tree
Showing 45 changed files with 597 additions and 4,346 deletions.
2 changes: 1 addition & 1 deletion backend/src/database/migrations/R__array_accum.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE AGGREGATE array_accum (ANYARRAY) (
CREATE OR REPLACE AGGREGATE array_accum (ANYARRAY) (
SFUNC = array_cat,
STYPE = ANYARRAY,
INITCOND = '{}'
Expand Down
8 changes: 7 additions & 1 deletion backend/src/database/repositories/memberRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,13 @@ class MemberRepository {
throw new Error404()
}

return rows[0]
const [data] = rows
const affiliations = await MemberRepository.getAffiliations(id, options)

return {
...data,
affiliations,
}
}

static getUsernameFromIdentities(identities: IMemberIdentity[]): IMemberUsername {
Expand Down
16 changes: 16 additions & 0 deletions backend/src/database/repositories/organizationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ class OrganizationRepository {
}
const toInsert = {
...lodash.pick(data, [
'displayName',
'description',
'headline',
'logo',
'importHash',
'isTeamOrganization',
'lastEnrichedAt',
Expand All @@ -127,6 +131,18 @@ class OrganizationRepository {
transaction,
})

// prepare attributes object
const attributes = {} as any

if (data.logo) {
attributes.logo = {
custom: [data.logo],
default: data.logo,
}
}

await this.updateOrgAttributes(record.id, { attributes }, options)

await captureApiChange(
options,
organizationCreateAction(record.id, async (captureState) => {
Expand Down
9 changes: 7 additions & 2 deletions backend/src/database/repositories/sequelizeRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
SequelizeQueryExecutor,
TransactionalSequelizeQueryExecutor,
} from '@crowd/data-access-layer/src/queryExecutor'
import { getDbConnection } from '@crowd/data-access-layer/src/database'
import { DbConnection, getDbConnection } from '@crowd/data-access-layer/src/database'
import {
API_CONFIG,
IS_TEST_ENV,
Expand Down Expand Up @@ -60,6 +60,11 @@ export default class SequelizeRepository {
temporal = await getTemporalClient(TEMPORAL_CONFIG)
}

let productDb: DbConnection | undefined
if (PRODUCT_DB_CONFIG) {
productDb = await getDbConnection(PRODUCT_DB_CONFIG)
}

return {
log: getServiceLogger(),
database: await databaseInit(),
Expand All @@ -71,7 +76,7 @@ export default class SequelizeRepository {
redis: await getRedisClient(REDIS_CONFIG, true),
unleash,
temporal,
productDb: await getDbConnection(PRODUCT_DB_CONFIG),
productDb,
}
}

Expand Down
17 changes: 12 additions & 5 deletions backend/src/services/organizationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,17 @@ export default class OrganizationService extends LoggerBase {
const primaryBackup = mergeAction.unmergeBackup.primary as IOrganizationUnmergeBackup
const secondaryBackup = mergeAction.unmergeBackup.secondary as IOrganizationUnmergeBackup

// identities
// Construct primary organization with best effort
for (const key of OrganizationService.ORGANIZATION_MERGE_FIELDS) {
if (
primaryBackup[key] !== organization[key] &&
secondaryBackup[key] === organization[key]
) {
organization[key] = primaryBackup[key] || null
}
}

// Remove identities coming from secondary backup
organization.identities = organization.identities.filter(
(i) =>
!secondaryBackup.identities.some(
Expand Down Expand Up @@ -380,10 +390,7 @@ export default class OrganizationService extends LoggerBase {

const backup = {
primary: {
...lodash.pick(
await OrganizationRepository.findById(originalId, this.options, segmentId),
OrganizationService.ORGANIZATION_MERGE_FIELDS,
),
...lodash.pick(original, OrganizationService.ORGANIZATION_MERGE_FIELDS),
identities: await OrganizationRepository.getIdentities([originalId], this.options),
memberOrganizations: await MemberOrganizationRepository.findRolesInOrganization(
originalId,
Expand Down
1 change: 0 additions & 1 deletion frontend/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ declare module '@vue/runtime-core' {
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
Expand Down
13 changes: 7 additions & 6 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"chartjs-adapter-moment": "^1.0.1",
"chartjs-plugin-annotation": "^2.2.1",
"chartkick": "^5.0.1",
"dayjs": "^1.11.12",
"element-plus": "^2.3.1",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.27.5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
<template>
<section v-bind="$attrs">
<div class="flex justify-between items-center pb-6">
<h6 class="text-h6">
Work history
</h6>
<div class="flex items-center">
<h6 class="text-h6">
Work history
</h6>
<div class="pl-1">
<lf-tooltip placement="bottom">
<template #content>
Work experiences are mostly obtained<br> via enrichment but can also be added <br>manually.
</template>
<lf-icon name="question-line" :size="16" class="text-gray-400" />
</lf-tooltip>
</div>
</div>
<lf-tooltip
v-if="hasPermission(LfPermission.memberEdit)"
content="Add work experience"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,68 @@
<template>
<lf-card>
<div class="p-5">
<lf-card v-bind="$attrs">
<div class="px-5 py-4 flex justify-between items-center">
<h6>Projects</h6>
<lf-tooltip content="Manage activities affiliation per project" placement="top-end">
<lf-button type="secondary" size="small" @click="isAffilationEditOpen = true">
<lf-icon name="settings-4-line" />
Activities affiliation
</lf-button>
</lf-tooltip>
</div>
<div>
<article
v-for="project in projects.slice(0, showMore ? projects.length : 3)"
:key="project.id"
class="border-b border-gray-100 px-5 py-4.5 flex items-center justify-between"
class="border-b last:border-0 border-gray-100 px-5 py-4"
>
<div class="flex items-center">
<lf-icon name="stack-line" :size="20" />
<p class="pl-2 text-medium font-semibold">
<div class="flex justify-between">
<p class="text-medium font-semibold">
{{ project.name }}
</p>
<div class="flex items-center pt-0.5">
<p v-if="project.activityCount" class="mr-1 text-gray-500 text-small">
{{ pluralize('activity', +project.activityCount, true) }} <span class="px-1">•</span>
</p>
<lf-button type="primary-link" size="small" @click="viewActivity(project.id)">
View activity
</lf-button>
</div>
</div>
<div class="flex items-center">
<p v-if="project.activityCount" class="mr-1 text-gray-500 text-small">
{{ pluralize('activity', +project.activityCount, true) }} <span class="px-1">•</span>
<div v-if="Object.keys(project.affiliations).length" class="flex items-center pt-1 text-gray-500 gap-2">
<p class="text-small">
Affiliation:
</p>
<lf-button type="primary-link" size="small" @click="viewActivity(project.id)">
View activity
</lf-button>
<lf-tooltip v-for="(aff, orgId) in project.affiliations" :key="orgId">
<template #content>
<p class="text-left">
<span class="font-semibold">Affiliation period:<br></span>
<span v-html="getAffilationPeriodText(aff)" />
</p>
</template>
<div class="flex items-center">
<lf-avatar :src="aff[0].organizationLogo" :name="aff[0].organizationName" :size="18" class="!rounded border border-gray-200 mr-1 mt-px">
<template #placeholder>
<div class="w-full h-full bg-gray-50 flex items-center justify-center">
<lf-icon name="community-line" :size="14" class="text-gray-400" />
</div>
</template>
</lf-avatar>
<router-link
:to="{
name: 'organizationView',
params: { id: orgId },
query: {
projectGroup: selectedProjectGroup?.id,
segmentId: aff[0].segmentId,
},
}"
class="cursor-pointer text-small leading-5 underline decoration-dashed text-gray-500
decoration-gray-500 underline-offset-4 hover:decoration-gray-900 hover:!text-black max-w-30 truncate"
>
{{ aff[0].organizationName }}
</router-link>
</div>
</lf-tooltip>
</div>
</article>
</div>
Expand All @@ -31,6 +72,11 @@
</lf-button>
</div>
</lf-card>
<lf-contributor-edit-affilations
v-if="isAffilationEditOpen"
v-model="isAffilationEditOpen"
:contributor="props.contributor"
/>
</template>

<script setup lang="ts">
Expand All @@ -39,8 +85,15 @@ import LfButton from '@/ui-kit/button/Button.vue';
import LfIcon from '@/ui-kit/icon/Icon.vue';
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { Contributor } from '@/modules/contributor/types/Contributor';
import { Contributor, ContributorAffiliation } from '@/modules/contributor/types/Contributor';
import pluralize from 'pluralize';
import LfTooltip from '@/ui-kit/tooltip/Tooltip.vue';
import LfContributorEditAffilations
from '@/modules/contributor/components/edit/affilations/contributor-affilations-edit.vue';
import LfAvatar from '@/ui-kit/avatar/Avatar.vue';
import { storeToRefs } from 'pinia';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import moment from 'moment/moment';
const props = defineProps<{
contributor: Contributor,
Expand All @@ -50,8 +103,28 @@ const router = useRouter();
const route = useRoute();
const showMore = ref<boolean>(false);
const isAffilationEditOpen = ref<boolean>(false);
const projects = computed(() => props.contributor.segments);
const { selectedProjectGroup } = storeToRefs(useLfSegmentsStore());
const getAffiliations = (projectId: string) => (props.contributor.affiliations || []).filter((affiliation) => affiliation.segmentId === projectId)
.reduce((obj: Record<string, ContributorAffiliation[]>, aff: ContributorAffiliation) => {
if (!obj[aff.organizationId]) {
return {
...obj,
[aff.organizationId]: [aff],
};
}
return {
...obj,
[aff.organizationId]: [...obj[aff.organizationId], aff],
};
}, {});
const projects = computed(() => props.contributor.segments.map((p) => ({
...p,
affiliations: getAffiliations(p.id),
})));
const viewActivity = (projectId: string) => {
router.replace({
Expand All @@ -62,6 +135,21 @@ const viewActivity = (projectId: string) => {
},
});
};
const getAffilationPeriodText = (affilations: ContributorAffiliation[]) => affilations.map(({ dateStart, dateEnd }) => {
const start = dateStart
? moment(dateStart).utc().format('MMM YYYY')
: 'Unknown';
const endDefault = dateStart ? 'Present' : 'Unknown';
const end = dateEnd
? moment(dateEnd).utc().format('MMM YYYY')
: endDefault;
if (start === end) {
return start;
}
return `${start} → ${end}`;
}).join(' <br> ');
</script>

<script lang="ts">
Expand Down
Loading

0 comments on commit f33aaea

Please sign in to comment.