feature/projects-all-the-way-down #3323

Merged
konrad merged 123 commits from feature/projects-all-the-way-down into main 2023-05-30 10:09:40 +00:00
3 changed files with 62 additions and 29 deletions
Showing only changes of commit 2579c33ee1 - Show all commits

View File

@ -0,0 +1,36 @@
<template>
<nav class="menu" v-if="favoriteProjects">

Didn't check / thought: I think to remember that menu is a class also coming from bulma.

If that's the case: does that mean that we pass these styles down here? Could we instead add the menu class inside ProjectsNavigation or wouldn't that work because of the recurrsion?

Didn't check / thought: I think to remember that `menu` is a class also coming from bulma. If that's the case: does that mean that we pass these styles down here? Could we instead add the menu class inside ProjectsNavigation or wouldn't that work because of the recurrsion?

Yes, .menu is a class from bulma.

does that mean that we pass these styles down here? Could we instead add the menu class inside ProjectsNavigation or wouldn't that work because of the recurrsion?

You mean adding the class into the styles definition of the ProjectsNavigation component?

Yes, `.menu` is a class from bulma. > does that mean that we pass these styles down here? Could we instead add the menu class inside ProjectsNavigation or wouldn't that work because of the recurrsion? You mean adding the class into the styles definition of the `ProjectsNavigation` component?
<ProjectsNavigation v-model="favoriteProjects" :can-edit-order="false"/>
</nav>
<nav class="menu">
<ProjectsNavigation v-model="projects" :can-edit-order="true"/>
</nav>
</template>
<script setup lang="ts">
import {computed} from 'vue'
import {useProjectStore} from '@/stores/projects'
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
const projectStore = useProjectStore()
await projectStore.loadProjects()

Call this in App.vue and add a isLoadingPromise that contains the returned promise of the loadProjects function to the projectStore which we then can await here instead.

Call this in `App.vue` and add a `isLoadingPromise` that contains the returned promise of the `loadProjects` function to the projectStore which we then can await here instead.

What would be the advantage of this? I feel like this would be a lot more complicated.

What would be the advantage of this? I feel like this would be a lot more complicated.

The loading of the projects would happen much earlier in the request chain.
Since they are an async dependency the optimal time to request the server would be the moment we know that we have are authenticated.
So I guess it Shouldn't be App but maybe contentAuth.

That's also the reason why we load all labels there.

The loading of the projects would happen much earlier in the request chain. Since they are an async dependency the optimal time to request the server would be the moment we know that we have are authenticated. So I guess it Shouldn't be App but maybe contentAuth. That's also the reason why we [load all labels there](https://kolaente.dev/vikunja/frontend/src/commit/74d688b8d20838b2e0dbbe47e04ae0305e48ec6e/src/components/home/contentAuth.vue#L117-L118).

I've now moved it to contentAuth but am using the isLoading property of the project store to show the loading state. That means I can't use the Suspense component, but the loading property already exists and is populated, might as well use it.

I've now moved it to `contentAuth` but am using the `isLoading` property of the project store to show the loading state. That means I can't use the `Suspense` component, but the loading property already exists and is populated, might as well use it.

That makes sense.
Now ProjectsNavigationWrapper.vue is so simple that it doesn't make sense to have it as dedicated component. The reason why it was created was for the Suspense, right?

That makes sense. Now `ProjectsNavigationWrapper.vue` is so simple that it doesn't make sense to have it as dedicated component. The reason why it was created was for the `Suspense`, right?

Yes, I created it only to use it with Suspense. Should I include its contents back into navigation?

Yes, I created it only to use it with `Suspense`. Should I include its contents back into `navigation`?

I think that would be better now. Sry for the back and forth.

I think that would be better now. Sry for the back and forth.

No worries, changed it back.

No worries, changed it back.
const projects = computed(() => projectStore.projectsArray
konrad marked this conversation as resolved Outdated

Non archived root projects seems like something that the store should provide as computed.

Non archived root projects seems like something that the store should provide as computed.

Done

Done
.filter(p => p.parentProjectId === 0 && !p.isArchived)
.sort((a, b) => a.position - b.position))
const favoriteProjects = computed(() => projectStore.projectsArray
.filter(p => !p.isArchived && p.isFavorite)
.map(p => ({
...p,
konrad marked this conversation as resolved Outdated

Probably because you use v-model instead of modelValue for ProjectsNavigation. I guess that when the template gets rendered it wants to bind to something like @update:modelValue="(newVal) => projects.value = newVal"

Probably because you use `v-model` instead of `modelValue` for ProjectsNavigation. I guess that when the template gets rendered it wants to bind to something like `@update:modelValue="(newVal) => projects.value = newVal"`

I've now changed it to :modelValue and that seems to work.

I've now changed it to `:modelValue` and that seems to work.
childProjects: [],
}))
konrad marked this conversation as resolved Outdated

favoriteProjects also seems like something a store should export.

`favoriteProjects` also seems like something a store should export.

Done

Done

The top menu shouldn't have a padding top that has the sole purpose of creating space to the silbling component above. Since I still only check the code and don't have this branch running locally I'm not sure if the padding extends the background or something like that instead.

If not this .menu should use margin-top:

.menu + .menu {
	margin-top: math.div($navbar-padding, 2);
}
The top menu shouldn't have a padding top that has the sole purpose of creating space to the silbling component above. Since I still only check the code and don't have this branch running locally I'm not sure if the padding extends the background or something like that instead. If not this `.menu` should use margin-top: ```scss .menu + .menu { margin-top: math.div($navbar-padding, 2); } ```

Done.

Done.
.sort((a, b) => a.position - b.position))
</script>
konrad marked this conversation as resolved Outdated

Why the mapping / returning of a copy?

Why the mapping / returning of a copy?

That was a relic, I've removed it now.

That was a relic, I've removed it now.
<style lang="scss" scoped>
.menu {
padding-top: math.div($navbar-padding, 2);
}
</style>

View File

@ -16,7 +16,12 @@
:class="{'is-visible': background}"
class="app-container-background background-fade-in d-print-none"
:style="{'background-image': background && `url(${background})`}"></div>
<navigation class="d-print-none"/>
<Suspense>
<navigation class="d-print-none"/>
<template #fallback>
Loading...
dpschen marked this conversation as resolved Outdated

Use components/misc/loading.vue

Use `components/misc/loading.vue`

That was an old test I did, I've now removed it.

That was an old test I did, I've now removed it.
</template>
</Suspense>
<main
class="app-content"
:class="[

View File

@ -48,47 +48,30 @@
</ul>
</nav>
<nav class="menu" v-if="favoriteProjects">
<ProjectsNavigation v-model="favoriteProjects" :can-edit-order="false"/>
</nav>
<Suspense>
dpschen marked this conversation as resolved Outdated

Move v-if to front

Move `v-if` to front

Done

Done
<ProjectsNavigationWrapper/>
<nav class="menu">
<ProjectsNavigation v-model="projects" :can-edit-order="true"/>
</nav>
<template #fallback>
<Loading/>
</template>
</Suspense>
<PoweredByLink/>
</aside>
</template>
<script setup lang="ts">
import {computed, onBeforeMount} from 'vue'
import {computed} from 'vue'
import PoweredByLink from '@/components/home/PoweredByLink.vue'
import Logo from '@/components/home/Logo.vue'
import Loading from '@/components/misc/loading.vue'
import {useBaseStore} from '@/stores/base'
import {useProjectStore} from '@/stores/projects'
import ProjectsNavigation from '@/components/home/ProjectsNavigation.vue'
import ProjectsNavigationWrapper from '@/components/home/ProjectsNavigationWrapper.vue'
const baseStore = useBaseStore()
const projectStore = useProjectStore()
const menuActive = computed(() => baseStore.menuActive)
// FIXME: async action will be unfinished when component mounts
onBeforeMount(async () => {
await projectStore.loadProjects()
})
const projects = computed(() => projectStore.projectsArray
.filter(p => p.parentProjectId === 0 && !p.isArchived)
.sort((a, b) => a.position - b.position))
const favoriteProjects = computed(() => projectStore.projectsArray
.filter(p => !p.isArchived && p.isFavorite)
.map(p => ({
...p,
childProjects: [],
}))
.sort((a, b) => a.position - b.position))
</script>
<style lang="scss" scoped>

Can we put this component inside a <Suspense>? Then we can use await methods directly and without onBeforeMount hook.

Can we put this component inside a `<Suspense>`? Then we can use `await` methods directly and without `onBeforeMount ` hook.

I've now moved the project navigation into a separate wrapper component so that we can show a loading spinner while projects are loading and still show the other navigation links (overview, labels, etc).

I've now moved the project navigation into a separate wrapper component so that we can show a loading spinner while projects are loading and still show the other navigation links (overview, labels, etc).

Ok. Will check

Ok. Will check
@ -150,7 +133,16 @@ const favoriteProjects = computed(() => projectStore.projectsArray
}
}
.menu {
padding-top: math.div($navbar-padding, 2);
.loader-container {
konrad marked this conversation as resolved Outdated

This class doesn't isn't used in the template

This class doesn't isn't used in the template

I've renamed it - it is coming from the Loader component.

I've renamed it - it is coming from the `Loader` component.
min-width: 100%;
height: 150px;
&.is-loading::after {
dpschen marked this conversation as resolved Outdated

This changes styles inside the component. If the styles need to be adjusted the component should be changed instead.

This changes styles inside the component. If the styles need to be adjusted the component should be changed instead.

The problem is the component is used in multiple places where this would need different sizes. The way to do this would probably be variants with a prop?

The problem is the component is used in multiple places where this would need different sizes. The way to do this would probably be variants with a prop?

Correct! The question to ask is also: do we even need so many different sizes or shouldn't they be more unied. For now I guess it's enough to answer this quesion for this usecase here.

Correct! The question to ask is also: do we even need so many different sizes or shouldn't they be more unied. For now I guess it's enough to answer this quesion for this usecase here.

I've now added this as a variant to the component. In doing this I discovered there are more styles and uses of that loader which we should refactor at some point. I would consider that out of scope for this PR though.

I've now added this as a variant to the component. In doing this I discovered there are more styles and uses of that loader which we should refactor at some point. I would consider that out of scope for this PR though.
width: 3rem;
height: 3rem;
top: calc(50% - 1.5rem);
dpschen marked this conversation as resolved Outdated

Missing space

Missing space

Done

Done
left: calc(50% - 1.5rem);
border-width: 3px;
}
}
</style>