New organizations (#1488)

* [WIP] Transfer organizations to own branch

* push progress

* Setup organizations page

* Add organizations grid to user profile

* Remove debug

* Add error handling for failed organization fetch

* Refactor organization page and settings

* Restructure to composition setup api

* checklist completion

* Apply suggestions from code review

Co-authored-by: Emma Alexia <emma@modrinth.com>

* Update pages/[type]/[id]/settings/index.vue

Co-authored-by: Emma Alexia <emma@modrinth.com>

* Update pages/[type]/[id]/settings/index.vue

Co-authored-by: Emma Alexia <emma@modrinth.com>

* Update pages/[type]/[id]/settings/index.vue

Co-authored-by: Emma Alexia <emma@modrinth.com>

* Update pages/[type]/[id]/settings/index.vue

Co-authored-by: Emma Alexia <emma@modrinth.com>

* Clean up org state management

* Refactor useClientTry to simplify code

* Remove unused code and update dependencies

* Refactor bulkEditLinks event handler

* Refactor organization management functions

* Update heading from "Creators" to "Members"

* Refactor team member invitation

* Refactor member management functions

* Implement validation on clientside for org names

* Name sanitization for fun characters

* Update onInviteTeamMember function parameters

* Remove name

* sidebar

* random rendering issue

* Conform to org removal

* Org no projects conditional

* Update organization links in dashboard

* Update Cards to universal-cards

* Refactor gallery upload permissions

* Refactor to sidebar pattern

* Update button classes in gallery and versions components

* Finish (most)

* almost finish

* Finish orgs :D

* Fix lint

* orgs fixes

* fix most things

* project settings

* convert grid to cards

* clean up unused test class

* Settings -> Manage

* add org view to org management

* Fix prop mounting issue

* fix analytics grid layout overflow

* fix multiselect breaking layout

* Refactor chart selection logic in ChartDisplay.vue

* Add transfer modal

---------

Co-authored-by: Jai A <jaiagr+gpg@pm.me>
Co-authored-by: Emma Alexia <emma@modrinth.com>
This commit is contained in:
Carter
2024-01-06 15:09:26 -08:00
committed by GitHub
parent 1108b0264e
commit d893765b24
44 changed files with 4092 additions and 1037 deletions

View File

@@ -154,6 +154,23 @@
</IntlFormatted>
</span>
</div>
<template v-if="organizations.length > 0">
<hr class="card-divider" />
<div class="stats-block__item">
<IntlFormatted :message-id="messages.profileOrganizations" />
<div class="organizations-grid">
<nuxt-link
v-for="org in organizations"
:key="org.id"
v-tooltip="org.name"
class="organization"
:to="`/organization/${org.slug}`"
>
<Avatar :src="org.icon_url" :alt="'Icon for ' + org.name" size="xs" />
</nuxt-link>
</div>
</div>
</template>
</template>
</div>
</div>
@@ -380,6 +397,10 @@ const messages = defineMessages({
id: 'profile.user-id',
defaultMessage: 'User ID: {id}',
},
profileOrganizations: {
id: 'profile.label.organizations',
defaultMessage: 'Organizations',
},
profileManageProjectsButton: {
id: 'profile.button.manage-projects',
defaultMessage: 'Manage projects',
@@ -419,7 +440,7 @@ const messages = defineMessages({
},
profileNoCollectionsLabel: {
id: 'profile.label.no-collections',
defaultMessage: 'This user has no collection!',
defaultMessage: 'This user has no collections!',
},
profileNoCollectionsAuthLabel: {
id: 'profile.label.no-collections-auth',
@@ -432,32 +453,38 @@ const messages = defineMessages({
},
})
let user, projects, collections
let user, projects, organizations, collections
try {
;[{ data: user }, { data: projects }, { data: collections }] = await Promise.all([
useAsyncData(`user/${route.params.id}`, () => useBaseFetch(`user/${route.params.id}`)),
useAsyncData(
`user/${route.params.id}/projects`,
() => useBaseFetch(`user/${route.params.id}/projects`),
{
transform: (projects) => {
for (const project of projects) {
project.categories = project.categories.concat(project.loaders)
project.project_type = data.$getProjectTypeForUrl(
project.project_type,
project.categories,
tags.value
)
}
;[{ data: user }, { data: projects }, { data: organizations }, { data: collections }] =
await Promise.all([
useAsyncData(`user/${route.params.id}`, () => useBaseFetch(`user/${route.params.id}`)),
useAsyncData(
`user/${route.params.id}/projects`,
() => useBaseFetch(`user/${route.params.id}/projects`),
{
transform: (projects) => {
for (const project of projects) {
project.categories = project.categories.concat(project.loaders)
project.project_type = data.$getProjectTypeForUrl(
project.project_type,
project.categories,
tags.value
)
}
return projects
},
}
),
useAsyncData(`user/${route.params.id}/collections`, () =>
useBaseFetch(`user/${route.params.id}/collections`, { apiVersion: 3 })
),
])
return projects
},
}
),
useAsyncData(`user/${route.params.id}/organizations`, () =>
useBaseFetch(`user/${route.params.id}/organizations`, {
apiVersion: 3,
})
),
useAsyncData(`user/${route.params.id}/collections`, () =>
useBaseFetch(`user/${route.params.id}/collections`, { apiVersion: 3 })
),
])
} catch {
throw createError({
fatal: true,
@@ -497,12 +524,18 @@ useSeoMeta({
})
const projectTypes = computed(() => {
const obj = { collection: true }
const obj = {}
if (collections.value.length > 0) {
obj.collection = true
}
for (const project of projects.value) {
obj[project.project_type] = true
}
delete obj.project
return Object.keys(obj)
})
const sumDownloads = computed(() => {
@@ -594,9 +627,24 @@ export default defineNuxtComponent({
</script>
<style lang="scss" scoped>
.organizations-grid {
// 5 wide
display: flex;
flex-wrap: wrap;
justify-content: start;
grid-gap: var(--gap-sm);
margin-top: 0.5rem;
}
.collections-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
@media screen and (max-width: 800px) {
grid-template-columns: repeat(1, 1fr);
}
gap: var(--gap-lg);
.collection-item {
@@ -658,6 +706,7 @@ export default defineNuxtComponent({
}
}
}
.user-header-wrapper {
display: flex;
margin: 0 auto -1.5rem;