Added missing activity types

This commit is contained in:
Alan Rynne
2021-07-14 10:37:43 +02:00
parent 61aeb90974
commit f1cd1a05fa
2 changed files with 329 additions and 159 deletions
+190 -69
View File
@@ -1,136 +1,257 @@
<template>
<v-card :link="modifier !== 'deleted'" :to="url">
<v-card :link="url !== null" :to="url">
<v-card-text class="pa-2">
<div :class="tagColor" class="rounded-pill pa-2 white--text d-inline-flex justify-center align-center">
<div
:class="tagColor"
class="rounded-pill pa-2 white--text d-inline-flex justify-center align-center"
>
<v-icon small color="white">{{ activityInfo.icon }}</v-icon>
</div>
<span class="pa-2">
<span v-if="type !== 'stream_permissions'">
{{ type | capitalize }}
<span class="font-weight-bold font-italic primary--text">{{ this.activityInfo.name }} </span>
<span>was {{ modifier }} </span>
<span v-if="type !== 'stream'">
in stream <span class="font-weight-bold font-italic primary--text">{{ this.stream ? this.stream.name : `[Deleted] ${this.activity.streamId}` }} </span>
<span class="font-weight-bold font-italic primary--text">
{{ activityInfo.name }}
</span>
<timeago :datetime="activity.time" class="font-italic"></timeago>
by
<v-chip small class="pl-0" v-if="user">
</span>
<span v-else>
<v-chip v-if="user" small class="pl-0">
<v-avatar color="grey lighten-3" class="mr-1">
<img :src="user.avatar || `https://robohash.org/` + this.activity.userId + `.png?size=40x40`"
:alt="user.name">
<img
:src="
targetUser.avatar || `https://robohash.org/` + targetUser.id + `.png?size=40x40`
"
:alt="targetUser.name"
/>
</v-avatar>
{{ user.name }}
</v-chip>
<v-progress-circular v-else indeterminate></v-progress-circular>
</span>
<span>{{ activityInfo.modifier }}</span>
<span id="streamAttribution" v-if="type !== 'stream' && type !== 'user'">
in stream
<span class="font-weight-bold font-italic primary--text">
{{ stream ? stream.name : `[Deleted] ${activity.streamId}` }}
</span>
</span>
<span>
<timeago :datetime="activity.time" class="font-italic ma-1"></timeago>
</span>
<span id="userAttribution" v-if="type != 'user'">
by
<v-chip v-if="user" small class="pl-0">
<v-avatar color="grey lighten-3" class="mr-1">
<img
:src="user.avatar || `https://robohash.org/` + activity.userId + `.png?size=40x40`"
:alt="user.name"
/>
</v-avatar>
{{ user.name }}
</v-chip>
<v-progress-circular v-else indeterminate></v-progress-circular>
</span>
</span>
</v-card-text>
</v-card>
</template>
<script>
import UserAvatar from "@/components/UserAvatar";
import gql from "graphql-tag";
import gql from 'graphql-tag'
export default {
components: { UserAvatar },
props: ["activity"],
components: {},
props: ['activity'],
apollo: {
user: {
query: gql`query($id: String) {
user(id: $id){
name
avatar
query: gql`
query($id: String) {
user(id: $id) {
name
avatar
}
}
}`,
`,
variables() {
id: this.activity.userId;
return {
id: this.activity.userId
}
}
},
targetUser: {
query() {
return gql`
query targetUser($id: String) {
user(id: $id) {
name
avatar
id
}
}
`
},
update: (data) => data.user,
variables() {
return {
id: this.activity.info.targetUser
}
},
skip() {
return this.activity.info.targetUser === null || this.activity.info.targetUser === undefined
}
},
stream: {
query: gql`query($id: String!){ stream(id: $id){name}}`,
query: gql`
query($id: String!) {
stream(id: $id) {
name
}
}
`,
variables() {
return {
id: this.activity.streamId
};
}
},
skip() {
return this.type === "stream";
return this.type === 'stream'
}
}
},
methods: {},
computed: {
modifier() {
return this.activity.actionType.split("_")[1] + "d";
return this.activity.actionType.split('_').pop()
},
type() {
return this.activity.actionType.split("_")[0];
var x = this.activity.actionType.split('_')
x.pop()
return x.join('_')
},
url(){
if(this.modifier === "deleted") return
switch (this.type){
case "stream":
url() {
if (this.modifier === 'delete' || this.modifier === 'remove') return null
switch (this.type) {
case 'stream':
return `/streams/${this.activity.streamId}`
case "branch":
return `/streams/${this.activity.streamId}/branches/${this.activity.info.branch.name}`
case "commit":
case 'stream_permissions':
return `/streams/${this.activity.streamId}`
case 'branch':
return `/streams/${this.activity.streamId}/branches/${this.activity.info.branch?.name}`
case 'commit':
return `/streams/${this.activity.streamId}/commits/${this.activity.resourceId}`
case 'user':
return '/profile'
default:
return null
}
},
activityInfo() {
switch (this.activity.actionType) {
case "stream_create":
case 'stream_create':
return {
icon: "mdi-cloud",
name: this.activity.info.stream?.name
};
case "stream_delete":
icon: 'mdi-cloud',
name: this.activity.info.stream?.name,
modifier: 'was created'
}
case 'stream_update':
return {
icon: "mdi-cloud-alert",
name: this.activity.streamId
};
case "commit_create":
icon: 'mdi-cloud',
name: this.activity.info.new?.name,
modifier: 'was updated'
}
case 'stream_delete':
return {
icon: "mdi-timeline-plus",
name: this.activity.resourceId
};
case "commit_delete":
icon: 'mdi-cloud-alert',
name: this.activity.streamId,
modifier: 'was deleted'
}
case 'stream_permissions_add':
return {
icon: "mdi-timeline-minus",
name: this.activity.resourceId
};
case "branch_create":
icon: 'mdi-cloud-alert',
name: this.targetUser.name,
modifier: 'was granted access as ' + this.activity.info.role.split(':')[1]
}
case 'stream_permissions_remove':
return {
icon: "mdi-source-branch-plus",
name: this.activity.info.branch.name
};
case "branch_delete":
icon: 'mdi-cloud-alert',
name: 'User',
modifier: 'was revoked access'
}
case 'commit_create':
return {
icon: "mdi-source-branch-minus",
name: this.activity.info.branch.name
};
icon: 'mdi-timeline-plus',
name: this.activity.resourceId,
modifier: 'was created'
}
case 'commit_delete':
return {
icon: 'mdi-timeline-minus',
name: this.activity.resourceId,
modifier: 'was deleted'
}
case 'branch_create':
return {
icon: 'mdi-source-branch-plus',
name: this.activity.info.branch.name,
modifier: 'was created'
}
case 'branch_delete':
return {
icon: 'mdi-source-branch-minus',
name: this.activity.info.branch.name,
modifier: 'was deleted'
}
case 'branch_update':
return {
icon: 'mdi-source-branch-sync',
name: this.activity.info.new.name,
modifier: 'was updated'
}
case 'user_create':
return {
icon: 'mdi-account-plus',
name: this.activity.info.user.name,
modifier: 'was created'
}
case 'user_update':
return {
icon: 'mdi-account-convert',
name: this.activity.info.new.name,
modifier: 'was updated'
}
case 'user_delete':
return {
icon: 'mdi-account-remove',
name: this.activity.resourceId,
modifier: 'was deleted'
}
default:
return {
icon: "mdi-question",
icon: 'mdi-box',
name: this.activity.actionType
};
}
}
},
tagColor() {
var split = this.activity.actionType.split("_");
var mod = split[1];
var split = this.activity.actionType.split('_')
var mod = split[split.length - 1]
console.log('mod', this.activity.actionType, mod)
switch (mod) {
case "create":
return "success";
case "delete":
return "error";
case 'create':
return 'success'
case 'add':
return 'success'
case 'delete':
return 'error'
case 'remove':
return 'error'
default:
return "primary";
return 'primary'
}
}
}
};
},
methods: {}
}
</script>
<style></style>
+139 -90
View File
@@ -1,82 +1,115 @@
<template>
<div>
<v-card elevation="0" class="my-5" flat>
<v-card-text class="pb-0 ">
<v-card-text class="pb-0">
<span>Filter activity feed</span>
<div class="d-flex">
<v-select v-model="activityFilter.type" :items="filterTypes" label="Activity type" dense clearable></v-select>
<v-menu ref="menub"
v-model="menu2"
:close-on-content-click="true"
transition="scale-transition"
offset-y
min-width="auto">
<v-select
v-model="activityFilter.type"
:items="filterSelect"
item-text="name"
item-value="type"
label="Activity type"
dense
clearable
></v-select>
<v-menu
ref="menub"
v-model="menu2"
:close-on-content-click="true"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }">
<v-text-field v-model="activityFilter.after"
label="After date"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
dense
clearable></v-text-field>
<v-text-field
v-model="activityFilter.after"
label="After date"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
dense
clearable
></v-text-field>
</template>
<v-date-picker v-model="activityFilter.after" no-title color="primary"></v-date-picker>
</v-menu>
<v-menu ref="menu"
v-model="menu"
:close-on-content-click="true"
transition="scale-transition"
offset-y
min-width="auto">
<v-menu
ref="menu"
v-model="menu"
:close-on-content-click="true"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }">
<v-text-field v-model="activityFilter.before"
label="Before date"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
dense
clearable></v-text-field>
<v-text-field
v-model="activityFilter.before"
label="Before date"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
dense
clearable
></v-text-field>
</template>
<v-date-picker v-model="activityFilter.before"
no-title
@cancel="activityFilter.before = null"
color="primary"></v-date-picker>
<v-date-picker
v-model="activityFilter.before"
no-title
@cancel="activityFilter.before = null"
color="primary"
></v-date-picker>
</v-menu>
</div>
</v-card-text>
</v-card>
<div key="activity-list" v-if="activityFeed">
<activity-item
v-for="activity in activityFeed.items"
:activity="activity"
:key="activity.time"
class="my-1"></activity-item>
<infinite-loading @infinite="infiniteHandler" key="infiniteLoader">
<div slot="no-more" class="pa-6 grey--text">No more activity results!</div>
<div slot="no-results" class="pa-12 grey--text">There are no streams to load</div>
</infinite-loading>
</div>
<div key="activity-list" v-if="activityFeed">
<activity-item
v-for="activity in activityFeed.items"
:activity="activity"
:key="activity.time"
class="my-1"
></activity-item>
<infinite-loading @infinite="infiniteHandler" key="infiniteLoader">
<div slot="no-more" class="pa-6 grey--text">No more activity results!</div>
<div slot="no-results" class="pa-12 grey--text">There are no streams to load</div>
</infinite-loading>
</div>
</div>
</template>
<script>
import ActivityItem from "@/components/ActivityItem";
import gql from "graphql-tag";
import InfiniteLoading from "vue-infinite-loading";
import ActivityItem from '@/components/ActivityItem'
import gql from 'graphql-tag'
import InfiniteLoading from 'vue-infinite-loading'
export default {
name: "ActivityFeed",
name: 'ActivityFeed',
components: { ActivityItem, InfiniteLoading },
props: {
type: String
},
mounted() {
},
mounted() {},
data() {
return {
filterTypes: ["branch_create", "branch_delete", "stream_create", "stream_delete", "commit_create", "commit_delete"],
filterTypes: [
'branch_create',
'branch_delete',
'branch_update',
'stream_create',
'stream_delete',
'stream_update',
'stream_permissions_add',
'stream_permissions_remove',
'commit_create',
'commit_delete',
'commit_udpate',
'user_update',
'user_create',
'user_delete'
],
activityFilter: {
type: null,
before: null,
@@ -86,63 +119,81 @@ export default {
menu2: false,
load: false,
showContent: false
};
}
},
apollo: {
activityFeed: {
query: gql`query($type: String, $before: DateTime, $after: DateTime) {
user {
id
activity(actionType: $type, before: $before, after: $after) {
totalCount
cursor
items {
actionType
userId
streamId
resourceId
resourceType
time
info
query: gql`
query($type: String, $before: DateTime, $after: DateTime) {
user {
id
activity(actionType: $type, before: $before, after: $after) {
totalCount
cursor
items {
actionType
userId
streamId
resourceId
resourceType
time
info
}
}
}
}
}`,
`,
variables() {
var obj = {
type: this.activityFilter.type,
before: this.activityFilter.before ? new Date(this.activityFilter.before).toISOString() : undefined,
after: this.activityFilter.after ? new Date(this.activityFilter.after).toISOString() : undefined
};
return obj;
before: this.activityFilter.before
? new Date(this.activityFilter.before).toISOString()
: undefined,
after: this.activityFilter.after
? new Date(this.activityFilter.after).toISOString()
: undefined
}
return obj
},
update: data => {
return data.user.activity;
update: (data) => {
return data.user.activity
}
}
},
computed: {
filterSelect() {
return this.filterTypes.map((t) => {
var split = t.split('_')
var name = `${split[0]} ${split[1]}`
return {
type: t,
name: name
}
})
}
},
methods: {
infiniteHandler($state) {
if (!this.activityFeed.cursor) {
$state.loaded();
$state.complete();
return;
$state.loaded()
$state.complete()
return
}
this.$apollo.queries.activityFeed.fetchMore({
variables: {
before: this.activityFeed.cursor,
after: this.activityFilter.after ? new Date(this.activityFilter.after).toISOString() : undefined
after: this.activityFilter.after
? new Date(this.activityFilter.after).toISOString()
: undefined
},
// Transform the previous result with new data
updateQuery: (previousResult, { fetchMoreResult }) => {
const newItems = fetchMoreResult.user.activity.items;
console.warn("new items", newItems);
const newItems = fetchMoreResult.user.activity.items
console.warn('new items', newItems)
//$state.complete()
//set vue-infinite state
if (newItems.length === 0)
$state.complete();
else
$state.loaded();
if (newItems.length === 0) $state.complete()
else $state.loaded()
return {
user: {
@@ -156,14 +207,12 @@ export default {
items: [...previousResult.user.activity.items, ...newItems]
}
}
};
}
}
});
})
}
}
};
}
</script>
<style scoped>
</style>
<style scoped></style>