Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collection View #47

Merged
merged 34 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
29520d8
Add Sidebar Template.
FledgeXu Aug 16, 2023
f5a9d98
Add the Basic Sidebar.
FledgeXu Aug 16, 2023
a842249
Add Project Selection Function.
FledgeXu Aug 17, 2023
66aca58
Add changing project name function.
FledgeXu Aug 17, 2023
8b256a3
Add deleting project function.
FledgeXu Aug 17, 2023
cbc8819
Add Redirect.
FledgeXu Aug 17, 2023
14423a9
Remove border.
FledgeXu Aug 17, 2023
f0add15
Fix the double deletion bug.
FledgeXu Aug 17, 2023
95f5ec0
Please CI complain.
FledgeXu Aug 17, 2023
f5fd50e
Rname css class name.
FledgeXu Aug 17, 2023
f8bc64a
Fix typos and name issues.
FledgeXu Aug 18, 2023
fccc407
Refactor modal component.
FledgeXu Aug 18, 2023
3bd1001
Add deletion confirm to project sidebar.
FledgeXu Aug 18, 2023
fb5251d
Add Contact and FAQ pages.
FledgeXu Aug 18, 2023
10cb2b0
Fix text vertical glitch.
FledgeXu Aug 18, 2023
1e5e6c3
Fix existed user view.
FledgeXu Aug 18, 2023
a73f39c
Change cursor type
FledgeXu Aug 18, 2023
5d2b9a1
Adjust sidebar width.
FledgeXu Aug 18, 2023
7a164d0
Add Enter and Esc action.
FledgeXu Aug 18, 2023
f08b005
Dragging files arrive to sidebar collection view.
FledgeXu Aug 18, 2023
e6be842
Check project expire date when files are uploaded.
FledgeXu Aug 18, 2023
4bbcbf6
Please CI.
FledgeXu Aug 18, 2023
e7b191f
Fix typo.
FledgeXu Aug 21, 2023
c607e4d
Add a cursor to indicate project is editable.
FledgeXu Aug 21, 2023
dac93de
Fix Edit actions.
FledgeXu Aug 21, 2023
88e236d
Fix Modal's wrong name.
FledgeXu Aug 21, 2023
21640ea
Trimming too long text.
FledgeXu Aug 21, 2023
fd90b7d
Break the reference.
FledgeXu Aug 21, 2023
1d37fd0
Revert name when updating failed.
FledgeXu Aug 21, 2023
d677a48
Stop showing Delete Button when it's in edit mode.
FledgeXu Aug 21, 2023
070a481
Fix wrong argument.
FledgeXu Aug 21, 2023
918f2d8
Format code.
FledgeXu Aug 21, 2023
01cc6dc
Format code.
FledgeXu Aug 21, 2023
be6381e
Fix format conflict.
FledgeXu Aug 21, 2023
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
12 changes: 3 additions & 9 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
<template>
<div class="d-flex flex-column vh-100" v-if="isReady">
<div class="flex-shrink-1">
<Suspense>
<RouterView />
</Suspense>
</div>
<FooterComponent />
</div>
<Suspense v-if="isReady">
<RouterView />
</Suspense>
<AlertsComponentVue />
</template>

<script setup lang="ts">
import AlertsComponentVue from './components/AlertsComponent.vue'
import FooterComponent from './components/FooterComponent.vue'
import { onMounted, ref } from 'vue'
import { useAppStore } from './stores/stores'

Expand Down
15 changes: 2 additions & 13 deletions frontend/src/components/DragToStartProjectComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ import DragToStartField from '@/components/DragToStartField.vue'
import { type Project } from '@/constants'
import type { User } from '@/constants'
import { useAppStore, useProjectIdStore, useInitialFilesStore } from '@/stores/stores'
import { createNewProject } from '@/utils'

const storeProjectId = useProjectIdStore()
const storeApp = useAppStore()
const storeInitialFiles = useInitialFilesStore()

async function createUserAndProject(): Promise<[User | null, Project | null]> {
const projectRequestData = {
name: 'First Project'
}
var user: User | null = null
var project: Project | null = null

Expand All @@ -30,16 +28,7 @@ async function createUserAndProject(): Promise<[User | null, Project | null]> {
return [user, project]
}

try {
const createProjectResponse = await storeApp.axiosInstance.post<Project>(
'/projects',
projectRequestData
)
project = createProjectResponse.data
} catch (error: any) {
console.log('Unable to create a new project.', error)
storeApp.alertsError('Unable to create a new project.')
}
project = await createNewProject('First Project')

return [user, project]
}
Expand Down
107 changes: 107 additions & 0 deletions frontend/src/components/ProjectColumnComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<template>
<div
class="px-2 py-2 my-2 d-flex justify-content-between align-items-center"
:class="{ active: isActive }"
@click.prevent="setupProject"
@dblclick.prevent="enableEditMode"
@mouseover="isHover = true"
@mouseleave="isHover = false"
>
<div class="d-flex align-items-center">
<div v-if="!isEditMode" class="text-light fs-4 pe-1 me-1">
<font-awesome-icon :icon="['fa', 'file']" />
</div>
<input
ref="inputElement"
v-else
type="text"
class="form-control"
v-model="projectName"
@blur="disableEditMode"
/>
<div v-if="!isEditMode" class="fw-semibold text-light">
{{ projectName }}
</div>
</div>
<div v-if="!isHover" class="expire text-white-50">
{{ leftDays }}
</div>
<button v-else type="button" class="btn text-light" @click.stop="deleteProject">
<font-awesome-icon :icon="['fas', 'trash']" />
</button>
</div>
</template>

<script setup lang="ts">
import type { Project } from '@/constants'
import { useAppStore, useProjectIdStore } from '@/stores/stores'
import moment from 'moment'
import { computed, ref, watch, type Ref } from 'vue'

const props = defineProps<{ project: Project }>()
const emit = defineEmits<{ deleteProject: [Project] }>()

const leftDays = computed(() =>
props.project.expire_on ? `Expire ${moment.utc(props.project.expire_on).fromNow()}` : ''
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
)
const storeProjectId = useProjectIdStore()
const isActive = computed(() => storeProjectId.projectId == props.project.id)
const isEditMode = ref(false)
const isHover = ref(false)
const projectName = ref(props.project.name)
const inputElement: Ref<HTMLInputElement | null> = ref(null)
const storeApp = useAppStore()

watch(inputElement, (newElement) => {
newElement?.focus()
})

function setupProject() {
storeProjectId.setProjectId(props.project.id)
}

function enableEditMode() {
isEditMode.value = true
}

async function disableEditMode() {
isEditMode.value = false
await updateProjectName(props.project.id, projectName.value)
}

async function updateProjectName(projectId: string, newName: string) {
const projectRequestData = {
name: newName
}
try {
await storeApp.axiosInstance.patch<Project>(`/projects/${projectId}`, projectRequestData)
} catch (error: any) {
console.log('Unable to update project name.', error, projectId)
storeApp.alertsError(`Unable to update project name, project id: ${projectId}`)
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
}
}

async function deleteProject() {
const toBeDeletedProject = props.project
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
if (isActive.value) {
storeProjectId.clearProjectId()
}
emit('deleteProject', toBeDeletedProject)
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
try {
await storeApp.axiosInstance.delete(`/projects/${toBeDeletedProject.id}`)
} catch (error: any) {
console.log('Unable to delete project.', error, props.project.id)
storeApp.alertsError(`Unable to delete project, project id: ${props.project.id}`)
}
}
</script>

<style scoped>
.expire {
font-size: 0.8em;
}

.active {
background-color: orange;
}
</style>
57 changes: 57 additions & 0 deletions frontend/src/components/SideBarComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<template>
<div class="d-flex flex-column" style="height: 100%">
<div class="d-flex justify-content-between mt-2 border-bottom border-2 border-white">
<div class="fw-bold fs-4 text-light">Collection:</div>
<button
type="button"
class="btn fw-bold fs-5 text-light p-1"
@click.prevent="createAndUpdateProject"
>
<font-awesome-icon :icon="['fas', 'plus']" />
</button>
</div>
<div class="flex-grow-1 py-2 overflow-x-auto">
<ProjectColumnComponent
v-for="project in projects"
:key="project.id"
:project="project"
@delete-project="deleteProject"
/>
</div>
<div class="border-top border-2 border-white py-2">
<p class="text-light">FAQ</p>
<p class="text-light">Contact</p>
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
</div>
</div>
</template>

<script setup lang="ts">
import ProjectColumnComponent from './ProjectColumnComponent.vue'
import type { Project } from '@/constants'
import { useAppStore } from '@/stores/stores'
import { createNewProject } from '@/utils'
import { ref, type Ref } from 'vue'
const storeApp = useAppStore()
const projects: Ref<Project[]> = ref([])

await updateProjects()

async function updateProjects() {
try {
const response = await storeApp.axiosInstance.get<Project[]>('/projects')
projects.value = response.data
} catch (error: any) {
console.log('Unable to retrieve projects info', error)
storeApp.alertsError('Unable to retrieve projects info')
}
}

async function createAndUpdateProject() {
await createNewProject('New Project')
await updateProjects()
}

function deleteProject(project: Project) {
projects.value = projects.value.filter((element) => element.id != project.id)
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
}
</script>
5 changes: 3 additions & 2 deletions frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import {
faFilePen,
faAngleDown,
faCheck,
faSort
faSort,
faFile
} from '@fortawesome/free-solid-svg-icons'

/* add icons to the library */
library.add(faPlus, faMinus, faXmark, faTrash, faFilePen, faAngleDown, faCheck, faSort)
library.add(faPlus, faMinus, faXmark, faTrash, faFilePen, faAngleDown, faCheck, faSort, faFile)

import App from './App.vue'
import router from './router'
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PrivacyAndCookieStatement from '@/views/PrivacyAndCookieStatement.vue'
import StartView from '@/views/StartView.vue'
import TermsOfService from '@/views/TermsOfService.vue'
import CollectionView from '@/views/CollectionView.vue'
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
Expand All @@ -10,6 +11,11 @@ const router = createRouter({
name: 'start',
component: StartView
},
{
path: '/collection',
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
name: 'collection',
component: CollectionView
},
{
path: '/privacy-and-cookie-statement',
name: 'PrivacyCookieStatement',
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,21 @@ export async function validateUser() {
}
return result
}

export async function createNewProject(name: string): Promise<Project | null> {
const storeApp = useAppStore()
const projectRequestData = {
name: name
}
try {
const createProjectResponse = await storeApp.axiosInstance.post<Project>(
'/projects',
projectRequestData
)
return createProjectResponse.data
} catch (error: unknown) {
console.log('Unable to create a new project.', error)
storeApp.alertsError('Unable to create a new project.')
return null
}
}
40 changes: 40 additions & 0 deletions frontend/src/views/CollectionView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="container-fluid vh-100">
<div class="row">
<div class="col col-3 sticky-top sidebar">
<SideBarComponent />
</div>
<div class="col content d-flex flex-column justify-content-between">
<div>
<ProjectView v-if="hasActivatedProject" />
</div>
<FooterComponent />
</div>
</div>
</div>
</template>

<script setup lang="ts">
import SideBarComponent from '@/components/SideBarComponent.vue'
import FooterComponent from '@/components/FooterComponent.vue'
import ProjectView from './ProjectView.vue'
import { useProjectIdStore } from '@/stores/stores'
import { computed } from 'vue'
const storeProjectId = useProjectIdStore()
const hasActivatedProject = computed(() => storeProjectId.projectId != null)
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
</script>

<style scoped>
.collection-container {
height: 100vh;
}

.sidebar {
background-color: var(--main-color);
height: 100vh;
}

.content {
min-height: 100vh;
}
</style>
10 changes: 9 additions & 1 deletion frontend/src/views/ProjectView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,15 @@ import {
} from '@/constants'
import { useAppStore, useProjectIdStore, useInitialFilesStore } from '@/stores/stores'
import axios from 'axios'
import { ref, type Ref, computed } from 'vue'
import { ref, type Ref, computed, watch } from 'vue'
import { storeToRefs } from 'pinia'

const isActive = ref(false)
const isEditMode = ref(false)
const isShowed = ref(true)
const storeApp = useAppStore()
const storeProjectId = useProjectIdStore()
const { projectId } = storeToRefs(storeProjectId)
const storeInitialFileStore = useInitialFilesStore()
const files: Ref<Map<string, ClientVisibleFile>> = ref(new Map())
const selectedFiles: Ref<Map<string, boolean>> = ref(new Map())
Expand All @@ -136,6 +138,12 @@ const sortedFiles: Ref<Map<string, ClientVisibleFile>> = computed(() =>
sortFiles(files.value, compareFunction.value)
)

watch(projectId, async () => {
files.value.clear()
const apiFiles = await getAllFiles(storeProjectId.projectId)
apiFiles.forEach((item) => files.value.set(item.id, { file: item, uploadedSize: item.filesize }))
})

if (storeInitialFileStore.initialFiles.length == 0) {
const apiFiles = await getAllFiles(storeProjectId.projectId)
apiFiles.forEach((item) => files.value.set(item.id, { file: item, uploadedSize: item.filesize }))
Expand Down
16 changes: 14 additions & 2 deletions frontend/src/views/StartView.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
<template>
<ProjectView v-if="isVaildProjectID" />
<HomeView v-else />
<div class="d-flex flex-column vh-100">
<div class="flex-shrink-1">
<Suspense>
<ProjectView v-if="isVaildProjectID" />
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
<HomeView v-else />
</Suspense>
</div>
<FooterComponent />
</div>
</template>

<script setup lang="ts">
import FooterComponent from '@/components/FooterComponent.vue'
import ProjectView from '@/views/ProjectView.vue'
import HomeView from '@/views/HomeView.vue'
import { type Project } from '@/constants'
Expand All @@ -12,6 +20,7 @@ import { useAppStore, useProjectIdStore } from '@/stores/stores'
import { validProjectID } from '@/utils'
import { validateUser } from '@/utils'
import { storeToRefs } from 'pinia'
import router from '@/router'

const storeProjectId = useProjectIdStore()
const { projectId } = storeToRefs(storeProjectId)
Expand Down Expand Up @@ -40,5 +49,8 @@ if (
(await validateUser())
) {
setupProjectId()
if (await validateUser()) {
router.push('/collection')
}
FledgeXu marked this conversation as resolved.
Show resolved Hide resolved
}
</script>