mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-03-13 15:39:18 +08:00
feat(frontend): allow sorting project list on user page (#1053)
This commit is contained in:
parent
f28d739eb2
commit
3878351289
@ -57,7 +57,7 @@ public class ProjectsController extends HangarComponent implements IProjectsCont
|
||||
|
||||
@Override
|
||||
@ApplicableFilters({ProjectCategoryFilter.class, ProjectPlatformFilter.class, ProjectAuthorFilter.class, ProjectQueryFilter.class, ProjectLicenseFilter.class, ProjectMCVersionFilter.class})
|
||||
@ApplicableSorters({SorterRegistry.VIEWS, SorterRegistry.DOWNLOADS, SorterRegistry.NEWEST, SorterRegistry.STARS, SorterRegistry.UPDATED, SorterRegistry.RECENT_DOWNLOADS, SorterRegistry.RECENT_VIEWS})
|
||||
@ApplicableSorters({SorterRegistry.VIEWS, SorterRegistry.DOWNLOADS, SorterRegistry.NEWEST, SorterRegistry.STARS, SorterRegistry.UPDATED, SorterRegistry.RECENT_DOWNLOADS, SorterRegistry.RECENT_VIEWS, SorterRegistry.SLUG})
|
||||
public ResponseEntity<PaginatedResult<Project>> getProjects(final String q, final boolean orderWithRelevance, final @NotNull RequestPagination pagination) {
|
||||
return ResponseEntity.ok(this.projectsApiService.getProjects(q, orderWithRelevance, pagination));
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ public enum SorterRegistry implements Sorter {
|
||||
NEWEST("newest", simpleSorter("hp.created_at")),
|
||||
UPDATED("updated", simpleSorter("last_updated_double")),
|
||||
RECENT_VIEWS("recent_views", simpleSorter("hp.recent_views")),
|
||||
RECENT_DOWNLOADS("recent_downloads", simpleSorter("hp.recent_downloads"));
|
||||
RECENT_DOWNLOADS("recent_downloads", simpleSorter("hp.recent_downloads")),
|
||||
SLUG("slug", simpleSorter("LOWER(hp.slug)"));
|
||||
|
||||
private static final Map<String, SorterRegistry> SORTERS = new HashMap<>();
|
||||
|
||||
|
@ -78,6 +78,7 @@ public interface ProjectsApiDAO {
|
||||
hp.category,
|
||||
hp.description,
|
||||
hp.last_updated AS dum, --- need to add this so we can use it in order by, special constraint on distinct queries
|
||||
LOWER(hp.slug) AS dum2,
|
||||
coalesce(hp.last_updated, hp.created_at) AS last_updated,
|
||||
((extract(EPOCH FROM coalesce(hp.last_updated, hp.created_at)) - 1609459200) / 604800) *1 AS last_updated_double, --- We can order with this. That "dum" does not work. It only orders it with this.
|
||||
hp.visibility,
|
||||
|
@ -140,7 +140,8 @@
|
||||
"newest": "Newest",
|
||||
"recentlyUpdated": "Recently Updated",
|
||||
"recentViews": "Recent Views",
|
||||
"recentDownloads": "Recent Downloads"
|
||||
"recentDownloads": "Recent Downloads",
|
||||
"slug": "Name"
|
||||
},
|
||||
"category": {
|
||||
"info": "Category",
|
||||
|
@ -1,10 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { User } from "hangar-api";
|
||||
import { PaginatedResult, Project, User } from "hangar-api";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { Organization } from "hangar-internal";
|
||||
import { computed, type FunctionalComponent } from "vue";
|
||||
import { computed, type FunctionalComponent, ref, watch } from "vue";
|
||||
import ProjectList from "~/components/projects/ProjectList.vue";
|
||||
import Card from "~/lib/components/design/Card.vue";
|
||||
import { avatarUrl } from "~/composables/useUrlHelper";
|
||||
@ -29,6 +29,8 @@ import LockUserModal from "~/components/modals/LockUserModal.vue";
|
||||
import ProjectCard from "~/components/projects/ProjectCard.vue";
|
||||
import OrgTransferModal from "~/components/modals/OrgTransferModal.vue";
|
||||
import OrgDeleteModal from "~/components/modals/OrgDeleteModal.vue";
|
||||
import InputSelect from "~/lib/components/ui/InputSelect.vue";
|
||||
import { useApi } from "~/composables/useApi";
|
||||
|
||||
const props = defineProps<{
|
||||
user: User;
|
||||
@ -38,7 +40,8 @@ const i18n = useI18n();
|
||||
|
||||
const route = useRoute();
|
||||
const userData = await useUserData(props.user.name);
|
||||
const { starred, watching, projects, organizations, pinned } = userData.value || { starred: null };
|
||||
const { starred, watching, organizations, pinned } = userData.value || { starred: null };
|
||||
const projects = ref(userData.value?.projects);
|
||||
let organizationVisibility = null;
|
||||
if (props.user.name === useAuthStore().user?.name) {
|
||||
organizationVisibility = await useOrgVisibility(props.user.name);
|
||||
@ -75,6 +78,19 @@ const buttons = computed<UserButton[]>(() => {
|
||||
|
||||
const isCurrentUser = computed<boolean>(() => authStore.user != null && authStore.user.name === props.user.name);
|
||||
|
||||
const sorters = [
|
||||
{ id: "-updated", label: i18n.t("project.sorting.recentlyUpdated") },
|
||||
{ id: "-newest", label: i18n.t("project.sorting.newest") },
|
||||
{ id: "-stars", label: i18n.t("project.sorting.mostStars") },
|
||||
{ id: "-downloads", label: i18n.t("project.sorting.mostDownloads") },
|
||||
{ id: "-recent_downloads", label: i18n.t("project.sorting.recentDownloads") },
|
||||
{ id: "slug", label: i18n.t("project.sorting.slug") },
|
||||
];
|
||||
const activeSorter = ref("-updated");
|
||||
watch(activeSorter, async () => {
|
||||
projects.value = await useApi<PaginatedResult<Project>>("projects", "get", { sort: activeSorter.value, owner: props.user.name });
|
||||
});
|
||||
|
||||
useHead(useSeo(props.user.name, props.user.name + " is an author on Hangar. " + props.user.tagline, route, avatarUrl(props.user.name)));
|
||||
</script>
|
||||
|
||||
@ -89,6 +105,14 @@ useHead(useSeo(props.user.name, props.user.name + " is an author on Hangar. " +
|
||||
|
||||
<div class="flex gap-4 flex-basis-full flex-col md:flex-row">
|
||||
<div class="flex-basis-full flex flex-col gap-2 flex-grow md:max-w-2/3 md:min-w-1/3">
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="basis-1/2">
|
||||
<h2 class="text-xl">{{ user.name }} has {{ projects.pagination.count }} projects</h2>
|
||||
</div>
|
||||
<div class="basis-1/2">
|
||||
<InputSelect v-model="activeSorter" :values="sorters" item-text="label" item-value="id"></InputSelect>
|
||||
</div>
|
||||
</div>
|
||||
<ProjectList :projects="projects"></ProjectList>
|
||||
</div>
|
||||
<div class="flex-basis-full flex-grow md:max-w-1/3 md:min-w-1/3">
|
||||
|
1
frontend/src/types/api.d.ts
vendored
1
frontend/src/types/api.d.ts
vendored
@ -1,4 +1,3 @@
|
||||
import { ref } from "vue";
|
||||
import { NamedPermission, Platform, ProjectCategory, Prompt } from "~/types/enums";
|
||||
import { Color, FlagReason, IPlatform, IProjectCategory, IPrompt, IVisibility } from "hangar-internal";
|
||||
import { IPermission, Role } from "hangar-api";
|
||||
|
Loading…
x
Reference in New Issue
Block a user