mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-24 14:24:47 +08:00
adjustments/improvements to pinned versions
This commit is contained in:
parent
1ec32bf8dd
commit
f10552bb75
@ -481,13 +481,14 @@
|
||||
"setRecommendedTooltip": "Set this version as recommended for {0} platform",
|
||||
"pinned": {
|
||||
"tooltip": {
|
||||
"false": "Pin this version to the main project page",
|
||||
"true": "Remove this pinned version from the main project page",
|
||||
"none": "Pin this version to the main project page",
|
||||
"version": "Remove this pinned version from the main project page",
|
||||
"channel": "This version is pinned via its channel"
|
||||
},
|
||||
"button": {
|
||||
"false": "Pin",
|
||||
"true": "Unpin"
|
||||
"none": "Pin",
|
||||
"version": "Unpin",
|
||||
"channel": "Unpin"
|
||||
},
|
||||
"request": {
|
||||
"true": "Successfully pinned this version",
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { NamedPermission, Platform, ReviewState, Visibility, ChannelFlag } from "~/types/enums";
|
||||
import { NamedPermission, Platform, ReviewState, Visibility, ChannelFlag, PinnedStatus } from "~/types/enums";
|
||||
import { HangarProject, HangarVersion, IPlatform } from "hangar-internal";
|
||||
import { computed, ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
@ -237,19 +237,17 @@ async function restoreVersion() {
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<template #content>
|
||||
<span v-if="!projectVersion.pinned && projectVersion.channel.flags.indexOf(ChannelFlag.PINNED) > -1">{{
|
||||
i18n.t("version.page.pinned.tooltip.channel")
|
||||
}}</span>
|
||||
<span v-else>{{ i18n.t(`version.page.pinned.tooltip.${projectVersion.pinned}`) }}</span>
|
||||
<span v-if="projectVersion.pinnedStatus === PinnedStatus.CHANNEL">{{ i18n.t("version.page.pinned.tooltip.channel") }}</span>
|
||||
<span v-else>{{ i18n.t(`version.page.pinned.tooltip.${projectVersion.pinnedStatus.toLowerCase()}`) }}</span>
|
||||
</template>
|
||||
<Button
|
||||
size="small"
|
||||
:disabled="!projectVersion.pinned && projectVersion.channel.flags.indexOf(ChannelFlag.PINNED) > -1"
|
||||
@click="setPinned(!projectVersion.pinned)"
|
||||
:disabled="projectVersion.pinnedStatus === PinnedStatus.CHANNEL"
|
||||
@click="setPinned(projectVersion.pinnedStatus === PinnedStatus.NONE)"
|
||||
>
|
||||
<IconMdiPinOff v-if="projectVersion.pinned" class="mr-1" />
|
||||
<IconMdiPinOff v-if="projectVersion.pinnedStatus !== PinnedStatus.NONE" class="mr-1" />
|
||||
<IconMdiPin v-else class="mr-1" />
|
||||
{{ i18n.t(`version.page.pinned.button.${projectVersion.pinned}`) }}
|
||||
{{ i18n.t(`version.page.pinned.button.${projectVersion.pinnedStatus.toLowerCase()}`) }}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
|
3
frontend/src/types/api/versions.d.ts
vendored
3
frontend/src/types/api/versions.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import { ChannelFlag } from "~/types/enums";
|
||||
import { ChannelFlag, PinnedStatus } from "~/types/enums";
|
||||
|
||||
declare module "hangar-api" {
|
||||
import type { Model, Named, ProjectNamespace, TagColor, Visible } from "hangar-api";
|
||||
@ -49,6 +49,7 @@ declare module "hangar-api" {
|
||||
tags: Tag[];
|
||||
channel: ProjectChannel;
|
||||
pinned: boolean;
|
||||
pinnedStatus: PinnedStatus;
|
||||
recommended: Platform[];
|
||||
}
|
||||
|
||||
|
@ -112,3 +112,9 @@ export enum ChannelFlag {
|
||||
SKIP_REVIEW_QUEUE = "SKIP_REVIEW_QUEUE",
|
||||
PINNED = "PINNED",
|
||||
}
|
||||
|
||||
export enum PinnedStatus {
|
||||
CHANNEL = "CHANNEL",
|
||||
RELEASE = "RELEASE",
|
||||
NONE = "NONE",
|
||||
}
|
||||
|
23
frontend/src/types/generated/icons.d.ts
vendored
23
frontend/src/types/generated/icons.d.ts
vendored
@ -5,7 +5,6 @@ import '@vue/runtime-core'
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
IconMdiAccountArrowRight: typeof import('~icons/mdi/account-arrow-right')['default']
|
||||
IconMdiAccountPlus: typeof import('~icons/mdi/account-plus')['default']
|
||||
IconMdiAlert: typeof import('~icons/mdi/alert')['default']
|
||||
IconMdiAlertBox: typeof import('~icons/mdi/alert-box')['default']
|
||||
@ -15,18 +14,12 @@ declare module '@vue/runtime-core' {
|
||||
IconMdiCalendar: typeof import('~icons/mdi/calendar')['default']
|
||||
IconMdiCheck: typeof import('~icons/mdi/check')['default']
|
||||
IconMdiCheckBold: typeof import('~icons/mdi/check-bold')['default']
|
||||
IconMdiCheckboxBlankCircleOutline: typeof import('~icons/mdi/checkbox-blank-circle-outline')['default']
|
||||
IconMdiCheckboxMarkedCircle: typeof import('~icons/mdi/checkbox-marked-circle')['default']
|
||||
IconMdiCheckCircle: typeof import('~icons/mdi/check-circle')['default']
|
||||
IconMdiCheckCircleOutline: typeof import('~icons/mdi/check-circle-outline')['default']
|
||||
IconMdiCheckDecagram: typeof import('~icons/mdi/check-decagram')['default']
|
||||
IconMdiCheckDecagramOutline: typeof import('~icons/mdi/check-decagram-outline')['default']
|
||||
IconMdiChevronDoubleDown: typeof import('~icons/mdi/chevron-double-down')['default']
|
||||
IconMdiCircle: typeof import('~icons/mdi/circle')['default']
|
||||
IconMdiClipboardOutline: typeof import('~icons/mdi/clipboard-outline')['default']
|
||||
IconMdiClose: typeof import('~icons/mdi/close')['default']
|
||||
IconMdiCloseCircle: typeof import('~icons/mdi/close-circle')['default']
|
||||
IconMdiCloudSearch: typeof import('~icons/mdi/cloud-search')['default']
|
||||
IconMdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
|
||||
IconMdiContentSave: typeof import('~icons/mdi/content-save')['default']
|
||||
IconMdiDelete: typeof import('~icons/mdi/delete')['default']
|
||||
@ -37,17 +30,11 @@ declare module '@vue/runtime-core' {
|
||||
IconMdiEye: typeof import('~icons/mdi/eye')['default']
|
||||
IconMdiEyeOff: typeof import('~icons/mdi/eye-off')['default']
|
||||
IconMdiFile: typeof import('~icons/mdi/file')['default']
|
||||
IconMdiFileFind: typeof import('~icons/mdi/file-find')['default']
|
||||
IconMdiFlag: typeof import('~icons/mdi/flag')['default']
|
||||
IconMdiFormatListNumbered: typeof import('~icons/mdi/format-list-numbered')['default']
|
||||
IconMdiHome: typeof import('~icons/mdi/home')['default']
|
||||
IconMdiInformation: typeof import('~icons/mdi/information')['default']
|
||||
IconMdiKeyOutline: typeof import('~icons/mdi/key-outline')['default']
|
||||
IconMdiLicense: typeof import('~icons/mdi/license')['default']
|
||||
IconMdiLink: typeof import('~icons/mdi/link')['default']
|
||||
IconMdiListStatus: typeof import('~icons/mdi/list-status')['default']
|
||||
IconMdiLockOpenOutline: typeof import('~icons/mdi/lock-open-outline')['default']
|
||||
IconMdiLockOutline: typeof import('~icons/mdi/lock-outline')['default']
|
||||
IconMdiMenu: typeof import('~icons/mdi/menu')['default']
|
||||
IconMdiMenuDown: typeof import('~icons/mdi/menu-down')['default']
|
||||
IconMdiOpenInNew: typeof import('~icons/mdi/open-in-new')['default']
|
||||
@ -56,20 +43,10 @@ declare module '@vue/runtime-core' {
|
||||
IconMdiPinOff: typeof import('~icons/mdi/pin-off')['default']
|
||||
IconMdiPlay: typeof import('~icons/mdi/play')['default']
|
||||
IconMdiPlus: typeof import('~icons/mdi/plus')['default']
|
||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
||||
IconMdiRenameBox: typeof import('~icons/mdi/rename-box')['default']
|
||||
IconMdiSend: typeof import('~icons/mdi/send')['default']
|
||||
IconMdiSort: typeof import('~icons/mdi/sort')['default']
|
||||
IconMdiSortAscending: typeof import('~icons/mdi/sort-ascending')['default']
|
||||
IconMdiSortDescending: typeof import('~icons/mdi/sort-descending')['default']
|
||||
IconMdiSortVariant: typeof import('~icons/mdi/sort-variant')['default']
|
||||
IconMdiStar: typeof import('~icons/mdi/star')['default']
|
||||
IconMdiStarOutline: typeof import('~icons/mdi/star-outline')['default']
|
||||
IconMdiStop: typeof import('~icons/mdi/stop')['default']
|
||||
IconMdiTag: typeof import('~icons/mdi/tag')['default']
|
||||
IconMdiTrophy: typeof import('~icons/mdi/trophy')['default']
|
||||
IconMdiUndo: typeof import('~icons/mdi/undo')['default']
|
||||
IconMdiUpload: typeof import('~icons/mdi/upload')['default']
|
||||
IconMdiWeatherNight: typeof import('~icons/mdi/weather-night')['default']
|
||||
IconMdiWhiteBalanceSunny: typeof import('~icons/mdi/white-balance-sunny')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
|
@ -35,7 +35,11 @@ public interface HangarVersionsDAO {
|
||||
" pc.name pc_name," +
|
||||
" pc.color pc_color," +
|
||||
" pc.flags pc_flags," +
|
||||
" exists(SELECT ppv.id FROM pinned_project_versions ppv WHERE ppv.version_id = pv.id) as pinned," +
|
||||
" CASE" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'channel') THEN 'CHANNEL'" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'version') THEN 'VERSION'" +
|
||||
" ELSE 'NONE'" +
|
||||
" END AS pinnedStatus," +
|
||||
" array(SELECT DISTINCT rpv.platform FROM recommended_project_versions rpv WHERE rpv.version_id = pv.id ORDER BY rpv.platform) as recommended," +
|
||||
" ru.name approved_by" +
|
||||
" FROM project_versions pv" +
|
||||
@ -73,7 +77,11 @@ public interface HangarVersionsDAO {
|
||||
" pc.name pc_name," +
|
||||
" pc.color pc_color," +
|
||||
" pc.flags pc_flags," +
|
||||
" exists(SELECT ppv.id FROM pinned_project_versions ppv WHERE ppv.version_id = pv.id) as pinned," +
|
||||
" CASE" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'channel') THEN 'CHANNEL'" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'version') THEN 'VERSION'" +
|
||||
" ELSE 'NONE'" +
|
||||
" END AS pinnedStatus," +
|
||||
" array(SELECT DISTINCT rpv.platform FROM recommended_project_versions rpv WHERE rpv.version_id = pv.id ORDER BY rpv.platform) as recommended," +
|
||||
" ru.name approved_by" +
|
||||
" FROM project_versions pv" +
|
||||
|
@ -50,7 +50,11 @@ public interface VersionsApiDAO {
|
||||
" pc.name pc_name," +
|
||||
" pc.color pc_color," +
|
||||
" pc.flags pc_flags," +
|
||||
" exists(SELECT ppv.id FROM pinned_project_versions ppv WHERE ppv.version_id = pv.id) as pinned," +
|
||||
" CASE" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'channel') THEN 'CHANNEL'" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'version') THEN 'VERSION'" +
|
||||
" ELSE 'NONE'" +
|
||||
" END AS pinnedStatus," +
|
||||
" array(SELECT DISTINCT rpv.platform FROM recommended_project_versions rpv WHERE rpv.version_id = pv.id ORDER BY rpv.platform) as recommended" +
|
||||
" FROM project_versions pv" +
|
||||
" JOIN project_channels pc ON pv.channel_id = pc.id" +
|
||||
@ -86,7 +90,11 @@ public interface VersionsApiDAO {
|
||||
" pc.name pc_name," +
|
||||
" pc.color pc_color," +
|
||||
" pc.flags pc_flags," +
|
||||
" exists(SELECT ppv.id FROM pinned_project_versions ppv WHERE ppv.version_id = pv.id) as pinned," +
|
||||
" CASE" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'channel') THEN 'CHANNEL'" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'version') THEN 'VERSION'" +
|
||||
" ELSE 'NONE'" +
|
||||
" END AS pinnedStatus," +
|
||||
" array(SELECT DISTINCT rpv.platform FROM recommended_project_versions rpv WHERE rpv.version_id = pv.id ORDER BY rpv.platform) as recommended" +
|
||||
" FROM project_versions pv" +
|
||||
" JOIN project_channels pc ON pv.channel_id = pc.id" +
|
||||
@ -125,7 +133,11 @@ public interface VersionsApiDAO {
|
||||
" pc.name pc_name," +
|
||||
" pc.color pc_color," +
|
||||
" pc.flags pc_flags," +
|
||||
" exists(SELECT ppv.id FROM pinned_project_versions ppv WHERE ppv.version_id = pv.id) as pinned," +
|
||||
" CASE" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'channel') THEN 'CHANNEL'" +
|
||||
" WHEN exists(SELECT * FROM pinned_versions piv WHERE piv.version_id = pv.id AND lower(type) = 'version') THEN 'VERSION'" +
|
||||
" ELSE 'NONE'" +
|
||||
" END AS pinnedStatus," +
|
||||
" array(SELECT DISTINCT rpv.platform FROM recommended_project_versions rpv WHERE rpv.version_id = pv.id ORDER BY rpv.platform) as recommended" +
|
||||
" FROM project_versions pv" +
|
||||
" JOIN projects p ON pv.project_id = p.id" +
|
||||
|
@ -18,8 +18,8 @@ public class Version extends VersionCompact {
|
||||
private final Map<Platform, Set<PluginDependency>> pluginDependencies;
|
||||
private final Map<Platform, Set<String>> platformDependencies;
|
||||
|
||||
public Version(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final boolean pinned, final List<Platform> recommended, final Long postId) {
|
||||
super(createdAt, name, visibility, description, stats, fileInfo, externalUrl, author, reviewState, channel, pinned, recommended, postId);
|
||||
public Version(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final PinnedStatus pinnedStatus, final List<Platform> recommended, final Long postId) {
|
||||
super(createdAt, name, visibility, description, stats, fileInfo, externalUrl, author, reviewState, channel, pinnedStatus, recommended, postId);
|
||||
this.pluginDependencies = new EnumMap<>(Platform.class);
|
||||
this.platformDependencies = new EnumMap<>(Platform.class);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.papermc.hangar.model.api.project.version;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.papermc.hangar.model.Model;
|
||||
import io.papermc.hangar.model.Named;
|
||||
import io.papermc.hangar.model.Visible;
|
||||
@ -11,6 +12,7 @@ import java.time.OffsetDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.jdbi.v3.core.enums.EnumByName;
|
||||
import org.jdbi.v3.core.enums.EnumByOrdinal;
|
||||
import org.jdbi.v3.core.mapper.Nested;
|
||||
import org.jdbi.v3.core.mapper.reflect.ColumnName;
|
||||
@ -27,11 +29,11 @@ public class VersionCompact extends Model implements Named, Visible {
|
||||
private final ReviewState reviewState;
|
||||
private final Set<Tag> tags;
|
||||
private final ProjectChannel channel;
|
||||
private final boolean pinned;
|
||||
private final PinnedStatus pinnedStatus;
|
||||
private final List<Platform> recommended;
|
||||
private final Long postId;
|
||||
|
||||
protected VersionCompact(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final boolean pinned, final List<Platform> recommended, final Long postId) {
|
||||
protected VersionCompact(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final PinnedStatus pinnedStatus, final List<Platform> recommended, final Long postId) {
|
||||
super(createdAt);
|
||||
this.name = name;
|
||||
this.visibility = visibility;
|
||||
@ -42,7 +44,7 @@ public class VersionCompact extends Model implements Named, Visible {
|
||||
this.author = author;
|
||||
this.reviewState = reviewState;
|
||||
this.channel = channel;
|
||||
this.pinned = pinned;
|
||||
this.pinnedStatus = pinnedStatus;
|
||||
this.tags = new HashSet<>();
|
||||
this.recommended = recommended;
|
||||
this.postId = postId;
|
||||
@ -90,8 +92,8 @@ public class VersionCompact extends Model implements Named, Visible {
|
||||
return this.channel;
|
||||
}
|
||||
|
||||
public boolean isPinned() {
|
||||
return this.pinned;
|
||||
public PinnedStatus getPinnedStatus() {
|
||||
return this.pinnedStatus;
|
||||
}
|
||||
|
||||
public List<Platform> getRecommended() {
|
||||
@ -101,4 +103,12 @@ public class VersionCompact extends Model implements Named, Visible {
|
||||
public Long getPostId() {
|
||||
return this.postId;
|
||||
}
|
||||
|
||||
@EnumByName
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
public enum PinnedStatus {
|
||||
NONE,
|
||||
VERSION,
|
||||
CHANNEL
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ public class HangarVersion extends Version implements Identified {
|
||||
private final long id;
|
||||
private final String approvedBy;
|
||||
|
||||
public HangarVersion(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final boolean pinned, final List<Platform> recommended, final long id, final String approvedBy, final long postId) {
|
||||
super(createdAt, name, visibility, description, stats, fileInfo, externalUrl, author, reviewState, channel, pinned, recommended, postId);
|
||||
public HangarVersion(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, @Nested("fi") final FileInfo fileInfo, final String externalUrl, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final PinnedStatus pinnedStatus, final List<Platform> recommended, final long id, final String approvedBy, final long postId) {
|
||||
super(createdAt, name, visibility, description, stats, fileInfo, externalUrl, author, reviewState, channel, pinnedStatus, recommended, postId);
|
||||
this.id = id;
|
||||
this.approvedBy = approvedBy;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ public class PinnedVersionService extends HangarComponent {
|
||||
}
|
||||
|
||||
public void addPinnedVersion(final long projectId, final long versionId) {
|
||||
// TODO check if already pinned via channel
|
||||
this.pinnedProjectVersionsDAO.insert(new PinnedProjectVersionTable(projectId, versionId));
|
||||
}
|
||||
|
||||
|
42
src/main/resources/db/migration/V1.0.5__fixItAgain.sql
Normal file
42
src/main/resources/db/migration/V1.0.5__fixItAgain.sql
Normal file
@ -0,0 +1,42 @@
|
||||
CREATE OR REPLACE VIEW pinned_versions AS
|
||||
SELECT * FROM (
|
||||
SELECT DISTINCT ON (version_id) version_id,
|
||||
id,
|
||||
created_at,
|
||||
type,
|
||||
version_string,
|
||||
platforms,
|
||||
project_id
|
||||
FROM (
|
||||
SELECT ppv.id,
|
||||
ppv.version_id,
|
||||
pv.created_at,
|
||||
pv.version_string,
|
||||
array(SELECT DISTINCT pv.platform FROM project_version_platform_dependencies pvpd
|
||||
JOIN platform_versions pv ON pv.id = pvpd.platform_version_id
|
||||
WHERE pvpd.platform_version_id = pv.id
|
||||
ORDER BY pv.platform
|
||||
) AS platforms,
|
||||
'version' AS type,
|
||||
pv.project_id
|
||||
FROM pinned_project_versions ppv
|
||||
JOIN project_versions pv ON pv.id = ppv.version_id
|
||||
UNION ALL
|
||||
(SELECT pc.id,
|
||||
pv.id AS version_id,
|
||||
pv.created_at,
|
||||
pv.version_string,
|
||||
array(SELECT DISTINCT pv.platform FROM project_version_platform_dependencies pvpd
|
||||
JOIN platform_versions pv ON pv.id = pvpd.platform_version_id
|
||||
WHERE pvpd.platform_version_id = pv.id
|
||||
ORDER BY pv.platform
|
||||
) AS platforms,
|
||||
'channel' as type,
|
||||
pv.project_id
|
||||
FROM project_channels pc
|
||||
JOIN project_versions pv ON pc.id = pv.channel_id
|
||||
WHERE 3 = ANY(pc.flags)
|
||||
ORDER BY pv.created_at DESC
|
||||
LIMIT 1)
|
||||
) AS pvs
|
||||
) AS t ORDER BY t.created_at DESC;
|
Loading…
Reference in New Issue
Block a user