Skip to content

Commit

Permalink
Merge branch 'main' into LFX-1168
Browse files Browse the repository at this point in the history
  • Loading branch information
Sameh16 authored Dec 17, 2024
2 parents d88fa7b + 81832aa commit 9bc1763
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@
</div>

<div v-if="!masked" class="flex flex-col gap-4">
<lf-contributor-details-work-history-item
v-for="org of (orgs || []).slice(0, showMore ? (orgs || []).length : 3)"
:key="org.id"
:contributor="props.contributor"
:organization="org"
@edit="isEditModalOpen = true; editOrganization = org"
/>
<div v-if="orgs.length === 0" class="pt-2 flex flex-col items-center">
<lf-timeline v-slot="{ group }" :groups="shownGroups" @on-group-hover="onGroupHover">
<lf-timeline-item v-for="item in group.items" :key="item.id" :data="item">
<lf-contributor-details-work-history-item
:contributor="props.contributor"
:organization="item"
:is-group-hover="hoveredGroup?.id === group.id"
@edit="isEditModalOpen = true; editOrganization = item"
/>
</lf-timeline-item>
</lf-timeline>
<div v-if="orgGrouped.length === 0" class="pt-2 flex flex-col items-center">
<lf-icon-old name="survey-line" :size="40" class="text-gray-300" />
<p class="text-center pt-3 text-medium text-gray-400">
No work experiences
Expand All @@ -55,7 +58,7 @@
</div>

<lf-button
v-if="!masked && orgs.length > 3"
v-if="!masked && orgGrouped.length > minimumShownGroups"
type="primary-link"
size="medium"
class="mt-6"
Expand Down Expand Up @@ -88,21 +91,52 @@ import LfContributorDetailsWorkHistoryItem
from '@/modules/contributor/components/details/work-history/contributor-details-work-history-item.vue';
import useContributorHelpers from '@/modules/contributor/helpers/contributor.helpers';
import LfIcon from '@/ui-kit/icon/Icon.vue';
import { TimelineGroup } from '@/ui-kit/timeline/types/TimelineTypes';
import { groupBy } from 'lodash';
import { storeToRefs } from 'pinia';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import LfTimeline from '@/ui-kit/timeline/Timeline.vue';
import LfTimelineItem from '@/ui-kit/timeline/TimelineItem.vue';
const props = defineProps<{
contributor: Contributor,
}>();
const { hasPermission } = usePermissions();
const { isMasked } = useContributorHelpers();
const { selectedProjectGroup } = storeToRefs(useLfSegmentsStore());
const showMore = ref<boolean>(false);
const isEditModalOpen = ref<boolean>(false);
const editOrganization = ref<Organization | null>(null);
const hoveredGroup = ref<TimelineGroup | null>(null);
const orgs = computed(() => props.contributor.organizations);
const orgGrouped = computed(() => {
const grouped = groupBy(props.contributor.organizations, 'id');
return Object.keys(grouped).map((id, index): TimelineGroup => ({
id: index,
label: grouped[id][0].displayName,
labelLink: {
name: 'organizationView',
params: {
id,
},
query: {
projectGroup: selectedProjectGroup.value?.id,
},
},
icon: grouped[id][0].logo,
items: grouped[id],
}));
});
const minimumShownGroups = 3;
const shownGroups = computed(() => orgGrouped.value.slice(0, showMore.value ? orgGrouped.value.length : minimumShownGroups));
const masked = computed(() => isMasked(props.contributor));
const onGroupHover = (index: TimelineGroup | null) => {
hoveredGroup.value = index;
};
</script>

<script lang="ts">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,10 @@
@mouseleave="hovered = false"
>
<div class="flex">
<lf-avatar
:name="props.organization.displayName"
:src="props.organization.logo"
:size="24"
class="!rounded-md border border-gray-200 min-w-6"
img-class="!object-contain"
>
<template #placeholder>
<div class="w-full h-full bg-gray-50 flex items-center justify-center">
<lf-icon-old name="community-line" :size="16" class="text-gray-400" />
</div>
</template>
</lf-avatar>

<div class="pl-3 flex flex-auto flex-col overflow-hidden">
<router-link
:to="{
name: 'organizationView',
params: {
id: props.organization.id,
},
query: {
projectGroup: selectedProjectGroup?.id,
},
}"
class="font-semibold text-medium leading-6 mb-1 truncate text-black hover:text-primary-500 transition block w-full overflow-hidden"
>
{{ props.organization.displayName }}
</router-link>

<div v-if="props.organization?.memberOrganizations?.title" class="text-small text-gray-500 mb-1.5 flex items-center gap-1.5">
<div class="flex flex-auto flex-col overflow-hidden">
<div v-if="props.organization?.memberOrganizations?.title" class="text-small text-gray-900 mb-1.5 flex items-center gap-1.5">
<lf-svg name="id-card" class="h-4 w-4 text-gray-400" />
<p class="truncate" style="max-width: 30ch">
<p class="truncate" style="max-width: 26ch">
{{ props.organization?.memberOrganizations?.title }}
</p>
</div>
Expand All @@ -46,7 +17,7 @@
</p>
</div>

<lf-dropdown v-if="hovered" placement="bottom-end" width="14.5rem">
<lf-dropdown v-if="hovered || isGroupHover" placement="bottom-end" width="14.5rem">
<template #trigger>
<lf-button type="secondary-ghost" size="small" :icon-only="true">
<lf-icon name="ellipsis" />
Expand Down Expand Up @@ -80,11 +51,8 @@
import LfIconOld from '@/ui-kit/icon/IconOld.vue';
import { Contributor } from '@/modules/contributor/types/Contributor';
import LfSvg from '@/shared/svg/svg.vue';
import LfAvatar from '@/ui-kit/avatar/Avatar.vue';
import { Organization } from '@/modules/organization/types/Organization';
import moment from 'moment';
import { storeToRefs } from 'pinia';
import { useLfSegmentsStore } from '@/modules/lf/segments/store';
import LfButton from '@/ui-kit/button/Button.vue';
import LfDropdown from '@/ui-kit/dropdown/Dropdown.vue';
import LfDropdownItem from '@/ui-kit/dropdown/DropdownItem.vue';
Expand All @@ -103,12 +71,12 @@ import LfIcon from '@/ui-kit/icon/Icon.vue';
const props = defineProps<{
organization: Organization,
contributor: Contributor
contributor: Contributor,
isGroupHover: boolean,
}>();
const emit = defineEmits<{(e:'edit'): void}>();
const { selectedProjectGroup } = storeToRefs(useLfSegmentsStore());
const { deleteContributorOrganization } = useContributorStore();
const { trackEvent } = useProductTracking();
Expand Down
53 changes: 53 additions & 0 deletions frontend/src/ui-kit/timeline/Timeline.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import LfSvg from '@/shared/svg/svg.vue';
import LfIconOld from '@/ui-kit/icon/IconOld.vue';
import LfTimeline from './Timeline.vue';
import LfTimelineItem from './TimelineItem.vue';
import { TimelineGroup } from './types/TimelineTypes';

export default {
title: 'LinuxFoundation/Timeline',
component: LfTimeline,
tags: ['autodocs'],
argTypes: {
groups: {
description: 'Timeline groups',
control: 'object',
},
},
};

export const Regular = {
args: {
groups: [
{
label: 'Group 1', labelLink: { name: 'organizationView', params: { id: '1' } }, icon: 'https://avatars.githubusercontent.com/u/38015056?v=4', items: [{ id: 1, label: 'Item 1', date: 'Aug 2024 - Dec 2024' }, { id: 2, label: 'Item 2', date: 'Aug 2024' }, { id: 3, label: 'Item 3', date: 'Aug 2024' }, { id: 4, label: 'Item 4', date: 'Aug 2024' }],
},
{
label: 'Group 2', labelLink: { name: 'organizationView', params: { id: '2' } }, icon: 'https://avatars.githubusercontent.com/u/38015056?v=4', items: [{ id: 3, label: 'Item 3', date: 'Aug 2024' }, { id: 4, label: 'Item 4', date: 'Aug 2024' }],
},
],
},
render: (args: { groups: TimelineGroup[] }) => ({
components: {
LfTimeline, LfTimelineItem, LfSvg, LfIconOld,
},
setup() {
return { args };
},
template: `<lf-timeline :groups="args.groups" v-slot="{ group }">
<lf-timeline-item :data="item" v-for="item in group.items" :key="item.id">
<!-- SAMPLE CONTENT -->
<div class="text-small text-gray-900 mb-1.5 flex items-center gap-1.5">
<lf-svg name="id-card" class="h-4 w-4 text-gray-400" />
<p class="truncate text-gray-900" style="max-width: 30ch">
{{ item.label }}
</p>
</div>
<p class="text-small text-gray-500 mb-1.5 flex items-center">
<lf-icon-old name="calendar-line" :size="16" class="mr-1.5 text-gray-400" />
{{ item.date }}
</p>
</lf-timeline-item>
</lf-timeline>`,
}),
};
60 changes: 60 additions & 0 deletions frontend/src/ui-kit/timeline/Timeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<div
v-for="group in props.groups"
:key="group.label"
class="c-timeline"
@mouseover="emit('onGroupHover', group)"
@mouseleave="emit('onGroupHover', null)"
>
<div class="c-timeline__group-icon">
<lf-avatar
:name="group.label"
:src="group.icon"
:size="24"
class="!rounded-md border border-gray-200 min-w-6"
img-class="!object-contain"
/>
</div>
<div class="grow">
<div class="c-timeline__group-label">
<router-link
v-if="group.labelLink"
:to="group.labelLink"
class="cursor-pointer text-gray-900 hover:text-primary-500"
>
{{ group.label }}
</router-link>
<span v-else>
{{ group.label }}
</span>
</div>

<div class="c-timeline__items">
<slot name="default" :group="group" :hovered="hovered" />
</div>
</div>
</div>
</template>

<script lang="ts" setup>
import LfAvatar from '@/ui-kit/avatar/Avatar.vue';
import { ref } from 'vue';
import { TimelineGroup } from './types/TimelineTypes';
const emit = defineEmits(['onGroupHover']);
const props = defineProps<{
groups: TimelineGroup[];
}>();
const hovered = ref(false);
</script>

<script lang="ts">
export default {
name: 'LfTimeline',
};
</script>

<style scoped lang="scss" src="./timeline.scss" />
19 changes: 19 additions & 0 deletions frontend/src/ui-kit/timeline/TimelineItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div class="c-timeline__item">
<div class="c-timeline__item-dot" />
<div class="c-timeline__item-content">
<slot :data="props.data" />
</div>
</div>
</template>

<script lang="ts" setup>
const props = defineProps<{
data: any;
}>();
</script>
<script lang="ts">
export default {
name: 'LfTimelineItem',
};
</script>
40 changes: 40 additions & 0 deletions frontend/src/ui-kit/timeline/timeline.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.c-timeline {
@apply flex items-start gap-3;
&__group-label {
@apply flex items-center font-semibold text-medium leading-6 mb-1 truncate text-black hover:text-primary-500 transition block w-full overflow-hidden;
}
// &__border {
// @apply w-px h-full bg-gray-200;
// }

::v-deep .c-timeline__item {
@apply relative mb-4;
.c-timeline__item-dot {
@apply w-3 h-3 z-[2] bg-gray-200 rounded-full absolute top-[2px] -left-[30px] border-3 border-white;
}
.c-timeline__item-content {
@apply relative;
&::before {
content: '';
@apply w-px bg-gray-200 absolute top-[2px] left-[-25px];
height: calc(100% + 25px);
}
}

&:first-child {
.c-timeline__item-dot {
@apply invisible;
}
}

&:last-child {
.c-timeline__item-content {
&::before {
@apply h-[5px];
}
}
}
}
}


9 changes: 9 additions & 0 deletions frontend/src/ui-kit/timeline/types/TimelineTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { RouteLocationRaw } from 'vue-router';

export interface TimelineGroup {
id: number;
label: string;
labelLink?: RouteLocationRaw;
icon?: string;
items: any[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export async function mergeMembers(
try {
await axios(url, requestOptions)
} catch (error) {
console.log(`Failed merging member wit status [${error.response.status}]. Skipping!`)
console.log(`Failed merging member wit status [${error.response?.status}]. Skipping!`)
}
}

Expand All @@ -156,6 +156,6 @@ export async function mergeOrganizations(
try {
await axios(url, requestOptions)
} catch (error) {
console.log(`Failed merging organization with status [${error.response.status}]. Skipping!`)
console.log(`Failed merging organization with status [${error.response?.status}]. Skipping!`)
}
}

0 comments on commit 9bc1763

Please sign in to comment.