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
931 changes: 917 additions & 14 deletions frontend/package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"@cubejs-client/vue3": "^0.31.0",
"@octokit/core": "^3.5.1",
"@tailwindcss/postcss7-compat": "^2.2.17",
"@tiptap/extension-placeholder": "^2.0.0-beta.199",
"@tiptap/starter-kit": "^2.0.0-beta.199",
"@tiptap/vue-3": "^2.0.0-beta.199",
"apollo-boost": "^0.4.9",
"axios": "^0.22.0",
"chart.js": "^3.7.0",
Expand All @@ -44,6 +47,7 @@
"remixicon": "^2.5.0",
"uuid": "8.3.0",
"vue": "^3.2.29",
"vue-3-sanitize": "^0.1.4",
"vue-grid-layout": "3.0.0-beta1",
"vue-json-pretty": "^2.2.2",
"vue-router": "^4.1.5",
Expand All @@ -53,6 +57,7 @@
"yup": "^0.32.11"
},
"devDependencies": {
"@tiptap/extension-link": "^2.0.0-beta.202",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.1",
"@vue/cli-service": "^5.0.1",
Expand Down
27 changes: 27 additions & 0 deletions frontend/src/assets/scss/content.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.c-content{
ul,
ol {
padding: 0 1rem;
}

p {
min-height: 20px;
}

ul {
list-style: initial;
}

ol {
list-style: number;
}

a {
@apply text-brand-500;
text-decoration: underline;
}

b, strong{
font-weight: 600;
}
}
1 change: 1 addition & 0 deletions frontend/src/assets/scss/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@
@import 'timeline';
@import 'badge';
@import 'radio';
@import 'content';

@import '~remixicon/fonts/remixicon.css';
7 changes: 7 additions & 0 deletions frontend/src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,13 @@ const en = {
}
},

note: {
fields: {
id: 'ID',
body: 'Note'
}
},

organization: {
name: 'organization',
label: 'Organizations',
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import ElementPlus from 'element-plus'
import VueGridLayout from 'vue-grid-layout'
import { AuthToken } from '@/modules/auth/auth-token'
import { TenantService } from '@/modules/tenant/tenant-service'
import Vue3Sanitize from 'vue-3-sanitize'

import App from '@/app.vue'
import { vueSanitizeOptions } from '@/plugins/sanitize'

i18nInit()
/**
Expand All @@ -32,6 +34,7 @@ i18nInit()

app.use(ElementPlus, { locale: getElementUILanguage() })
app.use(VueGridLayout)
app.use(Vue3Sanitize, vueSanitizeOptions)
app.config.productionTip =
process.env.NODE_ENV === 'production'

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/modules/activity/components/activity-content.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<blockquote
v-if="activity.thread && displayThread"
class="relative px-3 border-l-4 text-gray-500 border-gray-200 text-xs leading-5 mb-4"
v-html="activity.thread.body"
v-html="$sanitize(activity.thread.body)"
/>
<span
v-if="
Expand All @@ -54,7 +54,7 @@
:class="
showMore && !more ? `text-limit-${limit}` : ''
"
v-html="activity.body"
v-html="$sanitize(activity.body)"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
<div v-if="activity.parent && displayThread">
<blockquote
class="relative px-3 border-l-4 text-gray-500 border-gray-200 text-xs leading-5 mb-4"
v-html="activity.parent.body"
v-html="$sanitize(activity.parent.body)"
/>
</div>

<span
v-if="displayBody"
ref="body"
:class="bodyClass"
v-html="activity.body"
v-html="$sanitize(activity.body)"
/>
</div>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
<blockquote
v-if="activity.parent && displayThread"
class="relative px-3 border-l-4 text-gray-500 border-gray-200 text-xs leading-5 mb-4"
v-html="activity.parent.body"
v-html="$sanitize(activity.parent.body)"
/>
<span
v-if="displayBody"
ref="body"
class="block whitespace-pre-wrap custom-break-all"
:class="bodyClass"
v-html="activity.body"
v-html="$sanitize(activity.body)"
/>
</div>
</template>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<template>
<div class="member-view-activities panel">
<p class="font-medium text-gray-900">Activities</p>
<div class="member-view-activities">
<div class="my-6">
<el-input
v-model="query"
Expand Down Expand Up @@ -71,7 +70,7 @@
v-loading="loading"
class="app-page-spinner"
></div>
<div v-if="!noMore" class="flex justify-center">
<div v-if="!noMore" class="flex justify-center pt-4">
<el-button
class="btn btn-brand btn-brand--transparent"
:disabled="loading"
Expand Down Expand Up @@ -263,11 +262,8 @@ onMounted(async () => {
@apply max-w-full overflow-visible;
}
}
.member-view-activities-search
.el-input-group__append
.el-select
.el-input
.el-input__wrapper {
.member-view-activities-search .el-input-group__append,
.el-select .el-input .el-input__wrapper {
border-radius: 0 4px 4px 0 !important;
}
</style>
75 changes: 75 additions & 0 deletions frontend/src/modules/member/components/view/member-view-notes.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<div class="pt-8">
<app-note-editor
:properties="{ members: [props.member.id] }"
@created="fetchNotes()"
/>
</div>
<div v-if="notes.length > 0" class="pt-6">
<app-note-item
v-for="note of notes"
:key="note.id"
:note="note"
@reload="fetchNotes()"
/>
<div
v-if="notesCount > notes.length"
class="flex justify-center pt-4"
>
<el-button
class="btn btn-brand btn-brand--transparent"
@click="fetchNotes(notesPage + 1)"
><i class="ri-arrow-down-line"></i
><span class="text-xs">Load more</span></el-button
>
</div>
</div>
</template>

<script>
export default {
name: 'AppMemberViewNotes'
}
</script>

<script setup>
import { defineProps, onMounted, ref } from 'vue'
import AppNoteEditor from '@/modules/notes/components/note-editor'
import AppNoteItem from '@/modules/notes/components/note-item'
import { NoteService } from '@/modules/notes/note-service'

const props = defineProps({
member: {
type: Object,
required: true
}
})

const notes = ref([])
const notesCount = ref(0)
const notesPage = ref(0)
const notesLimit = 20

onMounted(() => {
fetchNotes()
})

const fetchNotes = (page = 0) => {
notesPage.value = page
NoteService.list(
{
members: [props.member.id]
},
'createdAt_DESC',
notesLimit,
notesPage.value * notesLimit
).then(({ rows, count }) => {
if (notesPage.value > 0) {
notes.value = [...notes.value, ...rows]
} else {
notes.value = rows
}
notesCount.value = count
})
}
</script>
21 changes: 17 additions & 4 deletions frontend/src/modules/member/pages/member-view-page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,21 @@
class="col-span-2"
/>
<app-member-view-aside :member="member" />
<app-member-view-activities
:member-id="member.id"
class="col-span-2"
/>
<div class="panel w-full col-span-2">
<el-tabs v-model="tab">
<el-tab-pane
label="Activities"
name="activities"
>
<app-member-view-activities
:member-id="member.id"
/>
</el-tab-pane>
<el-tab-pane label="Notes" name="notes">
<app-member-view-notes :member="member" />
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</app-page-wrapper>
Expand All @@ -42,6 +53,7 @@ import AppPageWrapper from '@/modules/layout/components/page-wrapper'
import AppMemberViewHeader from '@/modules/member/components/view/member-view-header'
import AppMemberViewAside from '@/modules/member/components/view/member-view-aside'
import AppMemberViewActivities from '@/modules/member/components/view/member-view-activities'
import AppMemberViewNotes from '@/modules/member/components/view/member-view-notes'

const store = useStore()
const props = defineProps({
Expand All @@ -56,6 +68,7 @@ const member = computed(() => {
})

const loading = ref(true)
const tab = ref('activities')

onMounted(async () => {
await store.dispatch('member/doFind', props.id)
Expand Down
82 changes: 82 additions & 0 deletions frontend/src/modules/notes/components/note-dropdown.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<template>
<div>
<el-dropdown
placement="bottom-end"
trigger="click"
@command="handleCommand"
@visible-change="dropdownVisible = $event"
>
<button
class="el-dropdown-link btn p-1.5 rounder-md hover:bg-gray-200 text-gray-600"
type="button"
@click.stop
>
<i class="text-xl ri-more-fill"></i>
</button>
<template #dropdown>
<el-dropdown-item command="noteEdit">
<i class="ri-pencil-line text-gray-400 mr-1" />
<span>Edit note</span></el-dropdown-item
>
<el-dropdown-item
command="noteDelete"
divided="divided"
>
<i class="ri-delete-bin-line text-red-500 mr-1" />
<span class="text-red-500">Delete note</span>
</el-dropdown-item>
</template>
</el-dropdown>
</div>
</template>

<script>
export default {
name: 'AppNoteDropdown'
}
</script>

<script setup>
import ConfirmDialog from '@/shared/confirm-dialog/confirm-dialog.js'
import { ref, defineEmits, defineProps } from 'vue'
import { NoteService } from '@/modules/notes/note-service'
import Message from '@/shared/message/message'

const emit = defineEmits(['edit', 'reload'])

const props = defineProps({
note: {
type: Object,
required: true
}
})

const dropdownVisible = ref(false)

const handleCommand = (command) => {
if (command === 'noteDelete') {
return doDestroyWithConfirm()
} else if (command === 'noteEdit') {
emit('edit')
}
}

const doDestroyWithConfirm = () => {
ConfirmDialog({
icon: 'ri-delete-bin-line',
type: 'danger',
title: 'Delete note',
message:
'Are you sure you want to proceed? You can’t undo this action',
confirmButtonText: 'Confirm',
cancelButtonText: 'Cancel'
})
.then(() => {
return NoteService.destroyAll([props.note.id])
})
.then(() => {
Message.success('Note successfully deleted!')
emit('reload')
})
}
</script>
Loading