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
19 changes: 19 additions & 0 deletions frontend/src/modules/activity/activity-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,25 @@ export class ActivityService {
return response.data;
}

static async listActivities(
body,
) {
const sampleTenant = AuthCurrentTenant.getSampleTenantData();
const tenantId = sampleTenant?.id || AuthCurrentTenant.get();

const response = await authAxios.post(
`/tenant/${tenantId}/activity/query`,
body,
{
headers: {
Authorization: sampleTenant?.token,
},
},
);

return response.data;
}

static async listAutocomplete(query, limit) {
const params = {
query,
Expand Down
101 changes: 51 additions & 50 deletions frontend/src/modules/activity/components/activity-list.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
<template>
<div class="pt-3">
<cr-filter
v-model="filters"
:config="activityFilters"
:search-config="activitySearchFilter"
hash="activity"
@fetch="fetch($event)"
/>
<div
v-if="loading && !activities.length"
v-loading="loading"
Expand All @@ -19,9 +26,9 @@
<div class="mb-4">
<app-pagination-sorter
v-model="sorterFilter"
:page-size="Number(pagination.pageSize)"
:total="count"
:current-page="pagination.currentPage"
:page-size="Number(pagination.perPage)"
:total="totalActivities"
:current-page="pagination.page"
:has-page-counter="false"
:sorter="false"
module="activity"
Expand All @@ -32,7 +39,7 @@
<!-- Activity item list -->
<app-activity-item
v-for="activity of activities"
:key="activity?.id"
:key="activity.id"
:activity="activity"
class="mb-6"
v-bind="cardOptions"
Expand Down Expand Up @@ -75,24 +82,18 @@ import {
computed,
ref,
} from 'vue';
import { useStore } from 'vuex';
import AppActivityItem from '@/modules/activity/components/activity-item.vue';
import AppConversationDrawer from '@/modules/conversation/components/conversation-drawer.vue';
import AppPaginationSorter from '@/shared/pagination/pagination-sorter.vue';
import CrFilter from '@/shared/modules/filters/components/Filter.vue';
import { useActivityStore } from '@/modules/activity/store/pinia';
import { storeToRefs } from 'pinia';
import { activityFilters, activitySearchFilter } from '@/modules/activity/config/filters/main';

const store = useStore();
const sorterFilter = ref('trending');
const conversationId = ref(null);

defineProps({
activities: {
type: Array,
default: () => {},
},
loading: {
type: Boolean,
default: false,
},
cardOptions: {
type: Object,
required: false,
Expand All @@ -102,52 +103,52 @@ defineProps({

const emit = defineEmits(['edit']);

const activeView = computed(
() => store.getters['activity/activeView'],
);
const hasFilter = computed(() => {
const parsedFilters = {
...activeView.value.filter.attributes,
};
const activityStore = useActivityStore();
const { filters, activities, totalActivities } = storeToRefs(activityStore);
const { fetchActivities } = activityStore;

// Remove search filter if value is empty
if (!parsedFilters.search?.value) {
delete parsedFilters.search;
}
const loading = ref(false);

return !!Object.keys(parsedFilters).length;
});
const emptyState = computed(() => {
if (hasFilter.value) {
return {
title: 'No activities found',
description:
const emptyState = computed(() => ({
title: 'No activities found',
description:
"We couldn't find any results that match your search criteria, please try a different query",
};
}
}));

return {
title: 'No activities yet',
description:
"We couldn't track any community member activities",
};
});

const count = computed(() => store.state.activity.count);
const pagination = computed(
() => store.getters['activity/pagination'],
() => filters.value.pagination,
);

const isLoadMoreVisible = computed(() => (
pagination.value.currentPage
* pagination.value.pageSize
< count.value
pagination.value.page
* pagination.value.perPage
< totalActivities
));

const onLoadMore = () => {
store.dispatch(
'activity/doChangePaginationCurrentPage',
pagination.value.currentPage + 1,
);
filters.value.pagination.page += 1;
};

const fetch = ({
filter, offset, limit, orderBy, body,
}) => {
loading.value = true;
fetchActivities({
...body,
filter: {
...filter,
member: {
isTeamMember: { not: true },
isBot: { not: true },
},
},
offset,
limit,
orderBy,
})
.finally(() => {
loading.value = false;
});
};
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
<template>
<cr-select-filter v-model="form" :options="options" />
<cr-select-filter v-model="form" :config="props.config as SelectFilterConfig" :options="data.options || []" />
</template>

<script setup lang="ts">
import { defineProps, defineEmits, computed } from 'vue';
import {
defineProps, defineEmits, computed, watch,
} from 'vue';
import CrSelectFilter from '@/shared/modules/filters/components/filterTypes/SelectFilter.vue';
import { SelectFilterOptionGroup } from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import {
SelectFilterConfig,
} from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import { CustomFilterConfig } from '@/shared/modules/filters/types/filterTypes/CustomFilterConfig';
import { useActivityTypeStore } from '@/modules/activity/store/type';
import { storeToRefs } from 'pinia';
import { CrowdIntegrations } from '@/integrations/integrations-config';

const props = defineProps<{
modelValue: string
modelValue: string,
config: CustomFilterConfig,
data: any,
}>();

const emit = defineEmits<{(e: 'update:modelValue', value: string)}>();
const emit = defineEmits<{(e: 'update:modelValue', value: string), (e: 'update:data', value: any),}>();
const activityTypeStore = useActivityTypeStore();
const { types } = storeToRefs(activityTypeStore);

const form = computed({
get: () => props.modelValue,
set: (value: string) => emit('update:modelValue', value),
});

// TODO: fetch activity types
const options: SelectFilterOptionGroup[] = [];
const data = computed({
get: () => props.data,
set: (value: any) => emit('update:data', value),
});
watch(() => types, (typesValue: any) => {
const platforms = {
...typesValue.value.default,
...typesValue.value.custom,
};
data.value.options = Object.entries(platforms).map(([platform, activityTypes]: [string, any]) => ({
label: CrowdIntegrations.getConfig(platform)?.name ?? platform,
options: Object.entries(activityTypes).map(([activityType, activityTypeData]) => ({
label: activityTypeData.display.short,
value: `${platform}:${activityType}`,
})),
}));
}, { immediate: true });
</script>
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FilterConfigType } from '@/shared/modules/filters/types/FilterConfig';
import { CustomFilterConfig } from '@/shared/modules/filters/types/filterTypes/CustomFilterConfig';
import ActivityTypeFilter from '@/modules/activity/config/filters/activityType/ActivityTypeFilter.vue';
import { SelectFilterValue } from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import { SelectFilterOptions, SelectFilterValue } from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import { queryUrlParserByType } from '@/shared/modules/filters/config/queryUrlParserByType';
import { itemLabelRendererByType } from '@/shared/modules/filters/config/itemLabelRendererByType';

const activityType: CustomFilterConfig = {
id: 'activityType',
Expand All @@ -13,12 +14,22 @@ const activityType: CustomFilterConfig = {
options: {
},
queryUrlParser: queryUrlParserByType[FilterConfigType.SELECT],
itemLabelRenderer(value: SelectFilterValue): string {
return `<b>Activity type</b> ${value || '...'}`;
itemLabelRenderer(value: SelectFilterValue, options: SelectFilterOptions, data: any): string {
return itemLabelRendererByType[FilterConfigType.SELECT]('Activity type', value, data, null, {
addGroupLabel: true,
});
},
apiFilterRenderer(value): any[] {
console.log(value);
return [];
apiFilterRenderer({ value, include }:SelectFilterValue): any[] {
const [platform, activityType] = value.split(':');
const filter = {
and: [
{ platform },
{ type: activityType },
],
};
return [
(include ? filter : { not: filter }),
];
},
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,49 @@
<template>
<cr-multi-select-filter v-model="form" :options="options" />
<cr-select-filter v-model="form" :config="props.config as SelectFilterConfig" :options="data.options || []" />
</template>

<script setup lang="ts">
import { defineProps, defineEmits, computed } from 'vue';
import CrMultiSelectFilter from '@/shared/modules/filters/components/filterTypes/MultiSelectFilter.vue';
import { MultiSelectFilterOptionGroup } from '@/shared/modules/filters/types/filterTypes/MultiSelectFilterConfig';
import {
defineProps, defineEmits, computed, watch,
} from 'vue';
import CrSelectFilter from '@/shared/modules/filters/components/filterTypes/SelectFilter.vue';
import {
SelectFilterConfig, SelectFilterOptionGroup,
} from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import { CustomFilterConfig } from '@/shared/modules/filters/types/filterTypes/CustomFilterConfig';
import { mapGetters } from '@/shared/vuex/vuex.helpers';
import { CrowdIntegrations } from '@/integrations/integrations-config';
import { extractRepoNameFromUrl } from '@/utils/string';

const props = defineProps<{
modelValue: string
modelValue: string,
config: CustomFilterConfig,
data: any,
}>();

const emit = defineEmits<{(e: 'update:modelValue', value: string)}>();
const emit = defineEmits<{(e: 'update:modelValue', value: string), (e: 'update:data', value: any),}>();

const { currentTenant } = mapGetters('auth');

const form = computed({
get: () => props.modelValue,
set: (value: string) => emit('update:modelValue', value),
});

// TODO: fetch activity types
const options: MultiSelectFilterOptionGroup[] = [];
const data = computed({
get: () => props.data,
set: (value: any) => emit('update:data', value),
});

watch(() => currentTenant.value, (tenant: any) => {
const activityChannels = tenant?.settings[0].activityChannels || {};

data.value.options = Object.entries(activityChannels).map(([platform, channels]): SelectFilterOptionGroup => ({
label: CrowdIntegrations.getConfig(platform).name,
options: channels.map((channel) => ({
value: channel,
label: platform === 'github' ? extractRepoNameFromUrl(channel) : channel,
})),
}));
}, { immediate: true });
</script>
19 changes: 12 additions & 7 deletions frontend/src/modules/activity/config/filters/channel/config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { FilterConfigType } from '@/shared/modules/filters/types/FilterConfig';
import { CustomFilterConfig } from '@/shared/modules/filters/types/filterTypes/CustomFilterConfig';
import { MultiSelectFilterValue } from '@/shared/modules/filters/types/filterTypes/MultiSelectFilterConfig';
import ChannelFilter from '@/modules/activity/config/filters/channel/ChannelFilter.vue';
import { queryUrlParserByType } from '@/shared/modules/filters/config/queryUrlParserByType';
import { SelectFilterOptions, SelectFilterValue } from '@/shared/modules/filters/types/filterTypes/SelectFilterConfig';
import { itemLabelRendererByType } from '@/shared/modules/filters/config/itemLabelRendererByType';

const channel: CustomFilterConfig = {
id: 'channel',
Expand All @@ -12,13 +13,17 @@ const channel: CustomFilterConfig = {
component: ChannelFilter,
options: {
},
queryUrlParser: queryUrlParserByType[FilterConfigType.MULTISELECT],
itemLabelRenderer(value: MultiSelectFilterValue): string {
return `<b>Channel</b> ${value || '...'}`;
queryUrlParser: queryUrlParserByType[FilterConfigType.SELECT],
itemLabelRenderer(value: SelectFilterValue, options: SelectFilterOptions, data: any): string {
return itemLabelRendererByType[FilterConfigType.SELECT]('Channel', value, data);
},
apiFilterRenderer(value): any[] {
console.log(value);
return [];
apiFilterRenderer({ value, include }:SelectFilterValue): any[] {
const filter = {
channel: value,
};
return [
(include ? filter : { not: filter }),
];
},
};

Expand Down
Loading