mirror of
https://github.com/HangarMC/Hangar.git
synced 2024-11-27 06:01:08 +08:00
userlist, announcement and other misc stuff
Signed-off-by: MiniDigger <admin@minidigger.me>
This commit is contained in:
parent
7e5e2b36af
commit
0e26eed9b5
@ -1,4 +1,5 @@
|
||||
@import '~vuetify/src/styles/styles.sass';
|
||||
@import 'utils';
|
||||
|
||||
.text-transform-unset {
|
||||
text-transform: unset;
|
||||
|
@ -7,3 +7,8 @@
|
||||
@mixin basic-border() {
|
||||
border: 1px solid $lighter;
|
||||
}
|
||||
|
||||
.flex-right {
|
||||
margin-left: auto;
|
||||
order: 2;
|
||||
}
|
||||
|
@ -117,7 +117,6 @@ export default class MarkdownEditor extends Vue {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page-btn {
|
||||
// TODO dynamic based on which buttons are shown
|
||||
left: 0;
|
||||
|
||||
&.edit-btn,
|
||||
|
@ -1,12 +1,44 @@
|
||||
<template>
|
||||
<!-- todo memberlist -->
|
||||
<div>Memberlist</div>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
{{ $t('project.members') }}
|
||||
<v-btn v-if="canEdit" icon class="flex-right" :to="manageUrl">
|
||||
<v-icon> mdi-pencil </v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-list v-if="members">
|
||||
<v-list-item v-for="member in members" :key="member.user.name">
|
||||
<UserAvatar :username="member.user.name" clazz="user-avatar-xs"></UserAvatar>
|
||||
<NuxtLink :to="'/' + member.user.name">{{ member.user.name }}</NuxtLink>
|
||||
<span class="flex-right">{{ member.role.role.title }}</span>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div v-else class="text-center py-4">
|
||||
<v-progress-circular indeterminate />
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
@Component({})
|
||||
export default class MemberList extends Vue {}
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
import { ProjectMember } from 'hangar-internal';
|
||||
import UserAvatar from '~/components/UserAvatar.vue';
|
||||
@Component({
|
||||
components: { UserAvatar },
|
||||
})
|
||||
export default class MemberList extends Vue {
|
||||
@Prop()
|
||||
members!: ProjectMember[];
|
||||
|
||||
@Prop()
|
||||
canEdit!: Boolean;
|
||||
|
||||
@Prop()
|
||||
manageUrl!: String;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
|
@ -29,10 +29,6 @@ export default class UserAvatar extends Vue {
|
||||
@Prop()
|
||||
clazz!: PropType<'user-avatar-md' | 'user-avatar-sm' | 'user-avatar-xs'>;
|
||||
|
||||
// attribute map // TODO implement
|
||||
@Prop()
|
||||
attr!: Object;
|
||||
|
||||
@Prop()
|
||||
href!: String;
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<v-list>
|
||||
<v-list-item v-for="user in users" :key="user.id">
|
||||
<UserAvatar :username="user.name" :avatar-url="$util.avatarUrl(user.name)" clazz="user-avatar-xs" />
|
||||
{{ user.name }}
|
||||
ROLE HERE
|
||||
<!-- todo role -->
|
||||
<v-list-item v-for="member in users" :key="member.user.name">
|
||||
<UserAvatar :username="member.user.name" clazz="user-avatar-xs"></UserAvatar>
|
||||
<NuxtLink :to="'/' + member.user.name">{{ member.user.name }}</NuxtLink>
|
||||
<span class="flex-right">{{ member.role.role.title }}</span>
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
<v-list-item>
|
||||
@ -17,15 +16,26 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { User } from 'hangar-api';
|
||||
import { ProjectMember } from 'hangar-internal';
|
||||
import UserAvatar from '~/components/UserAvatar.vue';
|
||||
import { RoleCategory } from '~/types/enums';
|
||||
|
||||
// TODO v-model for users
|
||||
@Component({
|
||||
components: { UserAvatar },
|
||||
})
|
||||
export default class UserSelectionForm extends Vue {
|
||||
users: Array<User> = [this.$util.dummyUser()];
|
||||
users: Array<ProjectMember> = [
|
||||
{
|
||||
user: this.$util.dummyUser(),
|
||||
role: {
|
||||
accepted: true,
|
||||
id: -1,
|
||||
createdAt: '',
|
||||
role: { title: 'Owner', value: 'owner', roleId: -1, category: RoleCategory.PROJECT, permission: '', color: { hex: '' } },
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -3,8 +3,7 @@
|
||||
<v-container>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col cols="12" class="d-flex justify-center">
|
||||
By using this site you're accepting our <a href="#"> Terms of Service</a
|
||||
><!-- todo tos link -->
|
||||
By using this site you're accepting our <a href="https://papermc.io/community-guidelines"> Terms of Service</a>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
@ -215,7 +215,6 @@ export default class Header extends Vue {
|
||||
|
||||
<style lang="scss">
|
||||
.v-badge--bordered.header-badge .v-badge__badge::after {
|
||||
// TODO variable for header background
|
||||
border-color: #272727 !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -3,7 +3,9 @@
|
||||
<Header />
|
||||
<v-main>
|
||||
<v-container>
|
||||
<Announcement v-for="(announcement, idx) in announcements" :key="idx" :announcement="announcement" />
|
||||
<template v-if="announcements">
|
||||
<Announcement v-for="(announcement, idx) in announcements" :key="idx" :announcement="announcement" />
|
||||
</template>
|
||||
|
||||
<DonationResult />
|
||||
<nuxt />
|
||||
@ -33,13 +35,10 @@ import DonationResult from '~/components/donation/DonationResult.vue';
|
||||
})
|
||||
export default class DefaultLayout extends Vue {
|
||||
title = 'Hangar';
|
||||
// TODO fetch from server
|
||||
announcements = [
|
||||
{
|
||||
text:
|
||||
'This is a staging server for testing purposes. Data could be deleted at any time. email confirmations are disabled. If you wanna help test, sneak into #hangar-dev',
|
||||
color: 'red lighten-1',
|
||||
},
|
||||
];
|
||||
announcements: Announcement[] = [];
|
||||
|
||||
async fetch() {
|
||||
this.announcements = await this.$api.requestInternal<Announcement[]>('data/announcements', false).catch<any>(this.$util.handlePageRequestError);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -68,6 +68,7 @@ const msgs: LocaleMessageObject = {
|
||||
noStargazers: 'There are no stargazers on this project yet :/',
|
||||
watchers: 'Watchers',
|
||||
noWatchers: 'There are no watchers on this project yet :/',
|
||||
members: 'Members',
|
||||
category: {
|
||||
info: 'Category: {0}',
|
||||
admin_tools: 'Admin Tools',
|
||||
|
@ -93,14 +93,12 @@
|
||||
<v-col cols="12">
|
||||
<ProjectPageList :project="project" />
|
||||
</v-col>
|
||||
<!-- todo member list -->
|
||||
<v-col cols="12">
|
||||
<MemberList />
|
||||
<!-- <MemberList-->
|
||||
<!-- :filtered-members-prop="filteredMembers"-->
|
||||
<!-- :can-manage-members="canManageMembers"-->
|
||||
<!-- :settings-call="ROUTES.parse('PROJECTS_SHOW_SETTINGS', project.ownerName, project.slug)"-->
|
||||
<!-- ></MemberList>-->
|
||||
<MemberList
|
||||
:members="project.members"
|
||||
:can-edit="$perms.canManageSubjectMembers"
|
||||
:manage-url="`/${project.namespace.owner}/${project.namespace.slug}/manage`"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
@ -109,8 +107,9 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component } from 'nuxt-property-decorator';
|
||||
import { ProjectPage } from 'hangar-internal';
|
||||
import { HangarProject, ProjectPage } from 'hangar-internal';
|
||||
import { Context } from '@nuxt/types';
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
import MarkdownEditor from '~/components/MarkdownEditor.vue';
|
||||
import Tag from '~/components/Tag.vue';
|
||||
import DonationModal from '~/components/donation/DonationModal.vue';
|
||||
@ -124,6 +123,9 @@ import ProjectPageList from '~/components/projects/ProjectPageList.vue';
|
||||
components: { ProjectPageList, NewPageModal, Markdown, MemberList, DonationModal, MarkdownEditor, Tag },
|
||||
})
|
||||
export default class DocsPage extends DocPageMixin {
|
||||
@Prop()
|
||||
project!: HangarProject;
|
||||
|
||||
async asyncData({ $api, params, $util }: Context) {
|
||||
const page = await $api.requestInternal<ProjectPage>(`pages/page/${params.author}/${params.slug}`, false).catch<any>($util.handlePageRequestError);
|
||||
return { page };
|
||||
|
@ -191,10 +191,13 @@
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<!-- todo memberlist (like index page -->
|
||||
<v-card>
|
||||
<v-card-title>Members</v-card-title>
|
||||
<v-card-text>...</v-card-text>
|
||||
<v-card-title>
|
||||
{{ $t('project.members') }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<UserSelectionForm :users="project.members" />
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
@ -202,11 +205,16 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'nuxt-property-decorator';
|
||||
import { HangarProject } from 'hangar-internal';
|
||||
import { Prop } from 'vue-property-decorator';
|
||||
import { ProjectPermission } from '~/utils/perms';
|
||||
import { NamedPermission, ProjectCategory } from '~/types/enums';
|
||||
import { RootState } from '~/store';
|
||||
|
||||
@Component
|
||||
import MemberList from '~/components/MemberList.vue';
|
||||
import UserSelectionForm from '~/components/UserSelectionForm.vue';
|
||||
@Component({
|
||||
components: { UserSelectionForm, MemberList },
|
||||
})
|
||||
@ProjectPermission(NamedPermission.EDIT_SUBJECT_SETTINGS)
|
||||
export default class ProjectManagePage extends Vue {
|
||||
apiKey = '';
|
||||
@ -228,6 +236,9 @@ export default class ProjectManagePage extends Vue {
|
||||
category: ProjectCategory.UNDEFINED,
|
||||
};
|
||||
|
||||
@Prop()
|
||||
project!: HangarProject;
|
||||
|
||||
get categoryIcon() {
|
||||
return (this.$store.state as RootState).projectCategories.get(this.form.category)?.icon;
|
||||
}
|
||||
|
14
frontend/types/internal/projects.d.ts
vendored
14
frontend/types/internal/projects.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
declare module 'hangar-internal' {
|
||||
import { Table, FlagReason } from 'hangar-internal';
|
||||
import { Project, User } from 'hangar-api';
|
||||
import { Project, Role, User } from 'hangar-api';
|
||||
|
||||
interface ProjectOwner {
|
||||
id: number;
|
||||
@ -25,9 +25,19 @@ declare module 'hangar-internal' {
|
||||
children: HangarProjectPage[];
|
||||
}
|
||||
|
||||
interface ProjectRole extends Table {
|
||||
accepted: true;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
interface ProjectMember {
|
||||
user: User;
|
||||
role: ProjectRole;
|
||||
}
|
||||
|
||||
interface HangarProject extends Project, Table {
|
||||
owner: ProjectOwner;
|
||||
members: object[];
|
||||
members: ProjectMember[];
|
||||
lastVisibilityChangeComment: string;
|
||||
lastVisibilityChangeUserName: string;
|
||||
info: HangarProjectInfo;
|
||||
|
@ -1,7 +1,7 @@
|
||||
package io.papermc.hangar.config.hangar;
|
||||
|
||||
import io.papermc.hangar.HangarApplication;
|
||||
import io.papermc.hangar.modelold.Announcement;
|
||||
import io.papermc.hangar.model.Announcement;
|
||||
import io.papermc.hangar.util.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
@ -12,6 +12,7 @@ import io.papermc.hangar.model.common.NamedPermission;
|
||||
import io.papermc.hangar.model.common.Platform;
|
||||
import io.papermc.hangar.model.common.projects.Category;
|
||||
import io.papermc.hangar.model.common.projects.FlagReason;
|
||||
import io.papermc.hangar.model.Announcement;
|
||||
import io.papermc.hangar.security.annotations.Anyone;
|
||||
import io.papermc.hangar.service.internal.projects.PlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -24,6 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@Controller
|
||||
@ -114,5 +116,10 @@ public class BackendDataController {
|
||||
public ResponseEntity<HangarConfig.Sponsor> getSponsor() {
|
||||
return ResponseEntity.ok(config.getSponsors().get(ThreadLocalRandom.current().nextInt(config.getSponsors().size())));
|
||||
}
|
||||
|
||||
@GetMapping("/announcements")
|
||||
public ResponseEntity<List<Announcement>> getAnnouncements() {
|
||||
return ResponseEntity.ok(config.getAnnouncements());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.papermc.hangar.modelold;
|
||||
package io.papermc.hangar.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
@ -1,5 +1,7 @@
|
||||
package io.papermc.hangar.model.common.roles;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.RoleCategory;
|
||||
import io.papermc.hangar.model.common.Color;
|
||||
import io.papermc.hangar.model.common.Permission;
|
||||
@ -8,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.postgresql.shaded.com.ongres.scram.common.util.Preconditions;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||
public enum OrganizationRole implements Role<OrganizationRoleTable> {
|
||||
|
||||
ORGANIZATION_SUPPORT("Organization_Support", 28, Permission.PostAsOrganization.add(Permission.IsOrganizationMember), "Support", Color.TRANSPARENT),
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.papermc.hangar.model.common.roles;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import io.papermc.hangar.db.customtypes.RoleCategory;
|
||||
import io.papermc.hangar.model.common.Color;
|
||||
import io.papermc.hangar.model.common.Permission;
|
||||
@ -8,6 +10,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.postgresql.shaded.com.ongres.scram.common.util.Preconditions;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||
public enum ProjectRole implements Role<ProjectRoleTable> {
|
||||
|
||||
PROJECT_SUPPORT("Project_Support", 22, Permission.IsProjectMember, "Support", Color.TRANSPARENT),
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.papermc.hangar.model.db.roles;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.papermc.hangar.model.common.roles.Role;
|
||||
import io.papermc.hangar.model.db.Table;
|
||||
@ -9,6 +10,7 @@ import java.time.OffsetDateTime;
|
||||
public abstract class ExtendedRoleTable<R extends Role<? extends IRoleTable<R>>> extends Table implements IRoleTable<R> {
|
||||
|
||||
protected final long userId;
|
||||
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||
protected final R role;
|
||||
protected boolean accepted;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user