diff --git a/server/lib/billing/tierMatrix.ts b/server/lib/billing/tierMatrix.ts index f0e6dc95a..7c0b591ca 100644 --- a/server/lib/billing/tierMatrix.ts +++ b/server/lib/billing/tierMatrix.ts @@ -23,7 +23,6 @@ export enum TierFeature { StandaloneHealthChecks = "standaloneHealthChecks", AlertingRules = "alertingRules", WildcardSubdomain = "wildcardSubdomain", - Labels = "labels", NewtAutoUpdate = "newtAutoUpdate", ResourcePolicies = "resourcePolicies", AdvancedPublicResources = "advancedPublicResources", @@ -31,7 +30,6 @@ export enum TierFeature { } export const tierMatrix: Record = { - [TierFeature.Labels]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.LoginPageDomain]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.DeviceApprovals]: ["tier1", "tier3", "enterprise"], diff --git a/server/private/routers/external.ts b/server/private/routers/external.ts index c6ee3de55..75a5b8d48 100644 --- a/server/private/routers/external.ts +++ b/server/private/routers/external.ts @@ -31,7 +31,6 @@ import * as siteProvisioning from "#private/routers/siteProvisioning"; import * as eventStreamingDestination from "#private/routers/eventStreamingDestination"; import * as alertRule from "#private/routers/alertRule"; import * as healthChecks from "#private/routers/healthChecks"; -import * as labels from "#private/routers/labels"; import * as client from "@server/routers/client"; import * as resource from "#private/routers/resource"; import * as policy from "#private/routers/policy"; @@ -810,59 +809,6 @@ authenticated.get( alertRule.getAlertRule ); -authenticated.get( - "/org/:orgId/labels", - verifyValidLicense, - verifyOrgAccess, - verifyValidSubscription(tierMatrix.labels), - verifyUserHasAction(ActionsEnum.listOrgLabels), - labels.listOrgLabels -); - -authenticated.post( - "/org/:orgId/labels", - verifyValidLicense, - verifyOrgAccess, - verifyValidSubscription(tierMatrix.labels), - verifyUserHasAction(ActionsEnum.createOrgLabel), - labels.createOrgLabel -); - -authenticated.patch( - "/org/:orgId/label/:labelId", - verifyValidLicense, - verifyOrgAccess, - verifyValidSubscription(tierMatrix.labels), - verifyUserHasAction(ActionsEnum.updateOrgLabel), - labels.updateOrgLabel -); - -authenticated.delete( - "/org/:orgId/label/:labelId", - verifyValidLicense, - verifyOrgAccess, - verifyUserHasAction(ActionsEnum.deleteOrgLabel), - labels.deleteOrgLabel -); - -authenticated.put( - "/org/:orgId/label/:labelId/attach", - verifyValidLicense, - verifyOrgAccess, - verifyValidSubscription(tierMatrix.labels), - verifyUserHasAction(ActionsEnum.attachLabelToItem), - labels.attachLabelToItem -); - -authenticated.put( - "/org/:orgId/label/:labelId/detach", - verifyValidLicense, - verifyOrgAccess, - verifyValidSubscription(tierMatrix.labels), - verifyUserHasAction(ActionsEnum.detachLabelFromItem), - labels.detachLabelFromItem -); - authenticated.get( "/org/:orgId/health-checks", verifyValidLicense, diff --git a/server/private/routers/labels/index.ts b/server/private/routers/labels/index.ts deleted file mode 100644 index d988d8e38..000000000 --- a/server/private/routers/labels/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - -export * from "./listOrgLabels"; -export * from "./createOrgLabel"; -export * from "./updateOrgLabel"; -export * from "./attachLabelToItem"; -export * from "./detachLabelFromItem"; -export * from "./deleteOrgLabel"; diff --git a/server/routers/client/listClients.ts b/server/routers/client/listClients.ts index 98c0fc550..3a05c41c5 100644 --- a/server/routers/client/listClients.ts +++ b/server/routers/client/listClients.ts @@ -304,11 +304,6 @@ export async function listClients( (client) => client.clientId ); - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - // Get client count with filter const conditions = [ and( @@ -341,7 +336,7 @@ export async function listClients( conditions.push(or(...filterAggregates)); } - if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) { + if (labelFilter && labelFilter.length > 0) { conditions.push( inArray( clients.clientId, @@ -361,25 +356,20 @@ export async function listClients( const q = "%" + query.toLowerCase() + "%"; const queryList = [ like(sql`LOWER(${clients.name})`, q), - like(sql`LOWER(${clients.niceId})`, q) + like(sql`LOWER(${clients.niceId})`, q), + inArray( + clients.clientId, + db + .select({ id: clientLabels.clientId }) + .from(clientLabels) + .innerJoin( + labels, + eq(labels.labelId, clientLabels.labelId) + ) + .where(like(sql`LOWER(${labels.name})`, q)) + ) ]; - if (isLabelFeatureEnabled) { - queryList.push( - inArray( - clients.clientId, - db - .select({ id: clientLabels.clientId }) - .from(clientLabels) - .innerJoin( - labels, - eq(labels.labelId, clientLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, q)) - ) - ); - } - conditions.push(or(...queryList)); } @@ -414,7 +404,7 @@ export async function listClients( clientId: number; }> = []; - if (isLabelFeatureEnabled && clientIds.length > 0) { + if (clientIds.length > 0) { labelsForClients = await db .select({ labelId: labels.labelId, diff --git a/server/routers/external.ts b/server/routers/external.ts index 8a22393ca..9e4c5b3f1 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -54,6 +54,7 @@ import { build } from "@server/build"; import { createStore } from "#dynamic/lib/rateLimitStore"; import { logActionAudit } from "#dynamic/middlewares"; import { checkRoundTripMessage } from "./ws"; +import * as labels from "@server/routers/labels"; // Root routes export const unauthenticated = Router(); @@ -1335,6 +1336,48 @@ authenticated.get( authenticated.get("/ws/round-trip-message/:messageId", checkRoundTripMessage); +authenticated.get( + "/org/:orgId/labels", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.listOrgLabels), + labels.listOrgLabels +); + +authenticated.post( + "/org/:orgId/labels", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.createOrgLabel), + labels.createOrgLabel +); + +authenticated.patch( + "/org/:orgId/label/:labelId", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.updateOrgLabel), + labels.updateOrgLabel +); + +authenticated.delete( + "/org/:orgId/label/:labelId", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.deleteOrgLabel), + labels.deleteOrgLabel +); + +authenticated.put( + "/org/:orgId/label/:labelId/attach", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.attachLabelToItem), + labels.attachLabelToItem +); + +authenticated.put( + "/org/:orgId/label/:labelId/detach", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.detachLabelFromItem), + labels.detachLabelFromItem +); + // Auth routes export const authRouter = Router(); unauthenticated.use("/auth", authRouter); diff --git a/server/private/routers/labels/attachLabelToItem.ts b/server/routers/labels/attachLabelToItem.ts similarity index 94% rename from server/private/routers/labels/attachLabelToItem.ts rename to server/routers/labels/attachLabelToItem.ts index d011a606d..0d9e49b35 100644 --- a/server/private/routers/labels/attachLabelToItem.ts +++ b/server/routers/labels/attachLabelToItem.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { clients, clientLabels, diff --git a/server/private/routers/labels/createOrgLabel.ts b/server/routers/labels/createOrgLabel.ts similarity index 91% rename from server/private/routers/labels/createOrgLabel.ts rename to server/routers/labels/createOrgLabel.ts index c856eecf4..6fa20816e 100644 --- a/server/private/routers/labels/createOrgLabel.ts +++ b/server/routers/labels/createOrgLabel.ts @@ -1,15 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ import { db, labels, diff --git a/server/private/routers/labels/deleteOrgLabel.ts b/server/routers/labels/deleteOrgLabel.ts similarity index 82% rename from server/private/routers/labels/deleteOrgLabel.ts rename to server/routers/labels/deleteOrgLabel.ts index f091c910a..c46e67437 100644 --- a/server/private/routers/labels/deleteOrgLabel.ts +++ b/server/routers/labels/deleteOrgLabel.ts @@ -1,15 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ import { db, labels } from "@server/db"; import response from "@server/lib/response"; import logger from "@server/logger"; diff --git a/server/private/routers/labels/detachLabelFromItem.ts b/server/routers/labels/detachLabelFromItem.ts similarity index 94% rename from server/private/routers/labels/detachLabelFromItem.ts rename to server/routers/labels/detachLabelFromItem.ts index 9a5545312..52c752ca8 100644 --- a/server/private/routers/labels/detachLabelFromItem.ts +++ b/server/routers/labels/detachLabelFromItem.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { clients, clientLabels, diff --git a/server/routers/labels/index.ts b/server/routers/labels/index.ts new file mode 100644 index 000000000..aa8c34222 --- /dev/null +++ b/server/routers/labels/index.ts @@ -0,0 +1,6 @@ +export * from "./listOrgLabels"; +export * from "./createOrgLabel"; +export * from "./updateOrgLabel"; +export * from "./attachLabelToItem"; +export * from "./detachLabelFromItem"; +export * from "./deleteOrgLabel"; diff --git a/server/private/routers/labels/listOrgLabels.ts b/server/routers/labels/listOrgLabels.ts similarity index 91% rename from server/private/routers/labels/listOrgLabels.ts rename to server/routers/labels/listOrgLabels.ts index dc2b50017..6d6b853cf 100644 --- a/server/private/routers/labels/listOrgLabels.ts +++ b/server/routers/labels/listOrgLabels.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { db, labels } from "@server/db"; import response from "@server/lib/response"; import logger from "@server/logger"; diff --git a/server/private/routers/labels/updateOrgLabel.ts b/server/routers/labels/updateOrgLabel.ts similarity index 89% rename from server/private/routers/labels/updateOrgLabel.ts rename to server/routers/labels/updateOrgLabel.ts index 134a01f02..fe8a6f573 100644 --- a/server/private/routers/labels/updateOrgLabel.ts +++ b/server/routers/labels/updateOrgLabel.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { db, labels } from "@server/db"; import response from "@server/lib/response"; import logger from "@server/logger"; diff --git a/server/routers/launcher/launcherResourceAccess.ts b/server/routers/launcher/launcherResourceAccess.ts index 246f86688..ec4500262 100644 --- a/server/routers/launcher/launcherResourceAccess.ts +++ b/server/routers/launcher/launcherResourceAccess.ts @@ -274,10 +274,7 @@ function combineOrConditions( return or(...parts); } -function buildSearchConditionForPublic( - query: string, - labelsFeatureEnabled: boolean -) { +function buildSearchConditionForPublic(query: string) { if (!query.trim()) { return undefined; } @@ -295,32 +292,21 @@ function buildSearchConditionForPublic( .leftJoin(sites, eq(targets.siteId, sites.siteId)) .leftJoin(exitNodes, eq(sites.exitNodeId, exitNodes.exitNodeId)) .where(like(sql`LOWER(${exitNodes.endpoint})`, pattern)) + ), + inArray( + resources.resourceId, + db + .select({ id: resourceLabels.resourceId }) + .from(resourceLabels) + .innerJoin(labels, eq(labels.labelId, resourceLabels.labelId)) + .where(like(sql`LOWER(${labels.name})`, pattern)) ) ]; - if (labelsFeatureEnabled) { - queryList.push( - inArray( - resources.resourceId, - db - .select({ id: resourceLabels.resourceId }) - .from(resourceLabels) - .innerJoin( - labels, - eq(labels.labelId, resourceLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, pattern)) - ) - ); - } - return or(...queryList); } -function buildSearchConditionForSiteResource( - query: string, - labelsFeatureEnabled: boolean -) { +function buildSearchConditionForSiteResource(query: string) { if (!query.trim()) { return undefined; } @@ -335,40 +321,34 @@ function buildSearchConditionForSiteResource( like(sql`LOWER(${siteResources.scheme})`, pattern), like(sql`LOWER(${siteResources.alias})`, pattern), like(sql`LOWER(${siteResources.fullDomain})`, pattern), - like(sql`LOWER(${siteResources.aliasAddress})`, pattern) + like(sql`LOWER(${siteResources.aliasAddress})`, pattern), + inArray( + siteResources.siteResourceId, + db + .select({ id: siteResourceLabels.siteResourceId }) + .from(siteResourceLabels) + .innerJoin( + labels, + eq(labels.labelId, siteResourceLabels.labelId) + ) + .where(like(sql`LOWER(${labels.name})`, pattern)) + ) ]; - if (labelsFeatureEnabled) { - queryList.push( - inArray( - siteResources.siteResourceId, - db - .select({ id: siteResourceLabels.siteResourceId }) - .from(siteResourceLabels) - .innerJoin( - labels, - eq(labels.labelId, siteResourceLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, pattern)) - ) - ); - } - return or(...queryList); } async function filterPublicResourceIdsByTextSearch( orgId: string, resourceIds: number[], - query: string, - labelsFeatureEnabled: boolean + query: string ): Promise { if (!query.trim() || resourceIds.length === 0) { return resourceIds; } const textMatch = combineOrConditions( - buildSearchConditionForPublic(query, labelsFeatureEnabled), + buildSearchConditionForPublic(query), buildSiteNameSearchCondition(query) ); if (!textMatch) { @@ -395,15 +375,14 @@ async function filterPublicResourceIdsByTextSearch( async function filterSiteResourceIdsByTextSearch( orgId: string, siteResourceIds: number[], - query: string, - labelsFeatureEnabled: boolean + query: string ): Promise { if (!query.trim() || siteResourceIds.length === 0) { return siteResourceIds; } const textMatch = combineOrConditions( - buildSearchConditionForSiteResource(query, labelsFeatureEnabled), + buildSearchConditionForSiteResource(query), buildSiteNameSearchCondition(query) ); if (!textMatch) { @@ -430,10 +409,6 @@ async function filterSiteResourceIdsByTextSearch( return rows.map((row) => row.siteResourceId); } -async function labelsEnabled(orgId: string): Promise { - return isLicensedOrSubscribed(orgId, tierMatrix.labels); -} - async function fetchLabelsForResources( orgId: string, resourceIds: number[], @@ -445,10 +420,6 @@ async function fetchLabelsForResources( const byResourceId = new Map(); const bySiteResourceId = new Map(); - if (!(await labelsEnabled(orgId))) { - return { byResourceId, bySiteResourceId }; - } - const [resourceLabelRows, siteResourceLabelRows] = await Promise.all([ resourceIds.length === 0 ? Promise.resolve([]) @@ -524,15 +495,8 @@ async function listSiteGroups( ): Promise<{ groups: LauncherGroup[]; total: number }> { const siteFilterIds = parseIdListParam(query.siteIds); const labelFilterIds = parseIdListParam(query.labelIds); - const labelsFeatureEnabled = await labelsEnabled(orgId); - const searchPublic = buildSearchConditionForPublic( - query.query, - labelsFeatureEnabled - ); - const searchSite = buildSearchConditionForSiteResource( - query.query, - labelsFeatureEnabled - ); + const searchPublic = buildSearchConditionForPublic(query.query); + const searchSite = buildSearchConditionForSiteResource(query.query); const siteCountMap = new Map(); if (accessible.resourceIds.length > 0) { @@ -775,10 +739,6 @@ async function listLabelGroups( >(); let unlabeledCount = 0; - if (!(await labelsEnabled(orgId))) { - return { groups: [], total: 0 }; - } - const matchesLabelFilters = (labelId: number) => labelFilterIds.length === 0 || labelFilterIds.includes(labelId); @@ -788,7 +748,7 @@ async function listLabelGroups( eq(resources.orgId, orgId), eq(resources.enabled, true) ]; - const searchPublic = buildSearchConditionForPublic(query.query, true); + const searchPublic = buildSearchConditionForPublic(query.query); if (searchPublic) { publicConditions.push(searchPublic); } @@ -852,10 +812,7 @@ async function listLabelGroups( eq(siteResources.orgId, orgId), eq(siteResources.enabled, true) ]; - const searchSite = buildSearchConditionForSiteResource( - query.query, - true - ); + const searchSite = buildSearchConditionForSiteResource(query.query); if (searchSite) { siteConditions.push(searchSite); } @@ -1302,23 +1259,19 @@ async function listLauncherResourcesForUserUncached( } } - const labelsFeatureEnabled = await labelsEnabled(orgId); - if (query.query.trim()) { if (filteredResourceIds.length > 0) { filteredResourceIds = await filterPublicResourceIdsByTextSearch( orgId, filteredResourceIds, - query.query, - labelsFeatureEnabled + query.query ); } if (filteredSiteResourceIds.length > 0) { filteredSiteResourceIds = await filterSiteResourceIdsByTextSearch( orgId, filteredSiteResourceIds, - query.query, - labelsFeatureEnabled + query.query ); } } @@ -1518,10 +1471,6 @@ async function collectAccessibleLabels( ): Promise> { const labelMap = new Map(); - if (!(await labelsEnabled(orgId))) { - return labelMap; - } - if (accessible.resourceIds.length > 0) { const publicConditions = [ inArray(resources.resourceId, accessible.resourceIds), diff --git a/server/routers/resource/getUserResources.ts b/server/routers/resource/getUserResources.ts index c82dcac48..92951ee1d 100644 --- a/server/routers/resource/getUserResources.ts +++ b/server/routers/resource/getUserResources.ts @@ -363,11 +363,6 @@ export async function getUserResources( (r) => r.siteResourceId ); - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - let labelsForResources: Array<{ labelId: number; name: string; @@ -381,49 +376,45 @@ export async function getUserResources( siteResourceId: number; }> = []; - if (isLabelFeatureEnabled) { - [labelsForResources, labelsForSiteResources] = await Promise.all([ - resourceIdList.length === 0 - ? Promise.resolve([]) - : db - .select({ - labelId: labels.labelId, - name: labels.name, - color: labels.color, - resourceId: resourceLabels.resourceId - }) - .from(labels) - .innerJoin( - resourceLabels, - eq(resourceLabels.labelId, labels.labelId) + [labelsForResources, labelsForSiteResources] = await Promise.all([ + resourceIdList.length === 0 + ? Promise.resolve([]) + : db + .select({ + labelId: labels.labelId, + name: labels.name, + color: labels.color, + resourceId: resourceLabels.resourceId + }) + .from(labels) + .innerJoin( + resourceLabels, + eq(resourceLabels.labelId, labels.labelId) + ) + .where(inArray(resourceLabels.resourceId, resourceIdList)) + .orderBy(asc(resourceLabels.resourceLabelId)), + siteResourceIdList.length === 0 + ? Promise.resolve([]) + : db + .select({ + labelId: labels.labelId, + name: labels.name, + color: labels.color, + siteResourceId: siteResourceLabels.siteResourceId + }) + .from(labels) + .innerJoin( + siteResourceLabels, + eq(siteResourceLabels.labelId, labels.labelId) + ) + .where( + inArray( + siteResourceLabels.siteResourceId, + siteResourceIdList ) - .where( - inArray(resourceLabels.resourceId, resourceIdList) - ) - .orderBy(asc(resourceLabels.resourceLabelId)), - siteResourceIdList.length === 0 - ? Promise.resolve([]) - : db - .select({ - labelId: labels.labelId, - name: labels.name, - color: labels.color, - siteResourceId: siteResourceLabels.siteResourceId - }) - .from(labels) - .innerJoin( - siteResourceLabels, - eq(siteResourceLabels.labelId, labels.labelId) - ) - .where( - inArray( - siteResourceLabels.siteResourceId, - siteResourceIdList - ) - ) - .orderBy(asc(siteResourceLabels.siteResourceLabelId)) - ]); - } + ) + .orderBy(asc(siteResourceLabels.siteResourceLabelId)) + ]); // Check for password, pincode, and whitelist protection for each resource const resourcesWithAuth = await Promise.all( diff --git a/server/routers/resource/listResources.ts b/server/routers/resource/listResources.ts index d1deb9d39..9567b5bcd 100644 --- a/server/routers/resource/listResources.ts +++ b/server/routers/resource/listResources.ts @@ -484,11 +484,6 @@ export async function listResources( ); } - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - let accessibleResources: Array<{ resourceId: number }>; if (req.user) { accessibleResources = await db @@ -676,7 +671,7 @@ export async function listResources( ); } - if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) { + if (labelFilter && labelFilter.length > 0) { conditions.push( inArray( resources.resourceId, @@ -697,25 +692,20 @@ export async function listResources( const queryList = [ like(sql`LOWER(${resources.name})`, q), like(sql`LOWER(${resources.niceId})`, q), - like(sql`LOWER(${resources.fullDomain})`, q) + like(sql`LOWER(${resources.fullDomain})`, q), + inArray( + resources.resourceId, + db + .select({ id: resourceLabels.resourceId }) + .from(resourceLabels) + .innerJoin( + labels, + eq(labels.labelId, resourceLabels.labelId) + ) + .where(like(sql`LOWER(${labels.name})`, q)) + ) ]; - if (isLabelFeatureEnabled) { - queryList.push( - inArray( - resources.resourceId, - db - .select({ id: resourceLabels.resourceId }) - .from(resourceLabels) - .innerJoin( - labels, - eq(labels.labelId, resourceLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, q)) - ) - ); - } - conditions.push(or(...queryList)); } @@ -747,27 +737,23 @@ export async function listResources( resourceId: number; }> = []; - if (isLabelFeatureEnabled) { - labelsForResources = - resourceIdList.length === 0 - ? [] - : await db - .select({ - labelId: labels.labelId, - name: labels.name, - color: labels.color, - resourceId: resourceLabels.resourceId - }) - .from(labels) - .innerJoin( - resourceLabels, - eq(resourceLabels.labelId, labels.labelId) - ) - .where( - inArray(resourceLabels.resourceId, resourceIdList) - ) - .orderBy(asc(resourceLabels.resourceLabelId)); - } + labelsForResources = + resourceIdList.length === 0 + ? [] + : await db + .select({ + labelId: labels.labelId, + name: labels.name, + color: labels.color, + resourceId: resourceLabels.resourceId + }) + .from(labels) + .innerJoin( + resourceLabels, + eq(resourceLabels.labelId, labels.labelId) + ) + .where(inArray(resourceLabels.resourceId, resourceIdList)) + .orderBy(asc(resourceLabels.resourceLabelId)); const allResourceTargets = resourceIdList.length === 0 diff --git a/server/routers/resource/listUserResourceAliases.ts b/server/routers/resource/listUserResourceAliases.ts index dab8afc23..4ec87b8bb 100644 --- a/server/routers/resource/listUserResourceAliases.ts +++ b/server/routers/resource/listUserResourceAliases.ts @@ -248,11 +248,6 @@ export async function listUserResourceAliases( }); } - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - const whereConditions = [ eq(siteResources.orgId, orgId), eq(siteResources.enabled, true), @@ -262,7 +257,7 @@ export async function listUserResourceAliases( inArray(siteResources.siteResourceId, accessibleSiteResourceIds) ]; - if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) { + if (labelFilter && labelFilter.length > 0) { whereConditions.push( inArray( siteResources.siteResourceId, @@ -310,7 +305,7 @@ export async function listUserResourceAliases( siteResourceId: number; }> = []; - if (isLabelFeatureEnabled && siteResourceIdList.length > 0) { + if (siteResourceIdList.length > 0) { labelsForSiteResources = await db .select({ name: labels.name, diff --git a/server/routers/site/listSites.ts b/server/routers/site/listSites.ts index 86c555f93..1f8e41f26 100644 --- a/server/routers/site/listSites.ts +++ b/server/routers/site/listSites.ts @@ -235,11 +235,6 @@ export async function listSites( ); } - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - const { pageSize, page, @@ -291,7 +286,7 @@ export async function listSites( conditions.push(eq(sites.status, status)); } - if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) { + if (labelFilter && labelFilter.length > 0) { conditions.push( inArray( sites.siteId, @@ -311,24 +306,20 @@ export async function listSites( const q = "%" + query.toLowerCase() + "%"; const queryList = [ like(sql`LOWER(${sites.name})`, q), - like(sql`LOWER(${sites.niceId})`, q) + like(sql`LOWER(${sites.niceId})`, q), + inArray( + sites.siteId, + db + .select({ id: siteLabels.siteId }) + .from(siteLabels) + .innerJoin( + labels, + eq(labels.labelId, siteLabels.labelId) + ) + .where(like(sql`LOWER(${labels.name})`, q)) + ) ]; - if (isLabelFeatureEnabled) { - queryList.push( - inArray( - sites.siteId, - db - .select({ id: siteLabels.siteId }) - .from(siteLabels) - .innerJoin( - labels, - eq(labels.labelId, siteLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, q)) - ) - ); - } conditions.push(or(...queryList)!); } @@ -366,25 +357,23 @@ export async function listSites( siteId: number; }> = []; - if (isLabelFeatureEnabled) { - labelsForSites = - siteIds.length === 0 - ? [] - : await db - .select({ - labelId: labels.labelId, - name: labels.name, - color: labels.color, - siteId: siteLabels.siteId - }) - .from(labels) - .innerJoin( - siteLabels, - eq(siteLabels.labelId, labels.labelId) - ) - .where(inArray(siteLabels.siteId, siteIds)) - .orderBy(asc(siteLabels.siteLabelId)); - } + labelsForSites = + siteIds.length === 0 + ? [] + : await db + .select({ + labelId: labels.labelId, + name: labels.name, + color: labels.color, + siteId: siteLabels.siteId + }) + .from(labels) + .innerJoin( + siteLabels, + eq(siteLabels.labelId, labels.labelId) + ) + .where(inArray(siteLabels.siteId, siteIds)) + .orderBy(asc(siteLabels.siteLabelId)); const sitesWithUpdates: SiteWithUpdateAvailable[] = rows.map((site) => { const siteWithUpdate: SiteWithUpdateAvailable = { ...site }; diff --git a/server/routers/siteResource/listAllSiteResourcesByOrg.ts b/server/routers/siteResource/listAllSiteResourcesByOrg.ts index 721d76bf6..4515e033e 100644 --- a/server/routers/siteResource/listAllSiteResourcesByOrg.ts +++ b/server/routers/siteResource/listAllSiteResourcesByOrg.ts @@ -286,11 +286,6 @@ export async function listAllSiteResourcesByOrg( labels: labelFilter } = parsedQuery.data; - const isLabelFeatureEnabled = await isLicensedOrSubscribed( - orgId, - tierMatrix.labels - ); - const conditions = [and(eq(siteResources.orgId, orgId))]; if (siteId != null) { @@ -320,7 +315,7 @@ export async function listAllSiteResourcesByOrg( conditions.push(eq(siteResources.mode, mode)); } - if (isLabelFeatureEnabled && labelFilter && labelFilter.length > 0) { + if (labelFilter && labelFilter.length > 0) { conditions.push( inArray( siteResources.siteResourceId, @@ -344,25 +339,20 @@ export async function listAllSiteResourcesByOrg( like(sql`LOWER(${siteResources.destination})`, q), like(sql`LOWER(${siteResources.alias})`, q), like(sql`LOWER(${siteResources.aliasAddress})`, q), - like(sql`LOWER(${sites.name})`, q) + like(sql`LOWER(${sites.name})`, q), + inArray( + siteResources.siteResourceId, + db + .select({ id: siteResourceLabels.siteResourceId }) + .from(siteResourceLabels) + .innerJoin( + labels, + eq(labels.labelId, siteResourceLabels.labelId) + ) + .where(like(sql`LOWER(${labels.name})`, q)) + ) ]; - if (isLabelFeatureEnabled) { - queryList.push( - inArray( - siteResources.siteResourceId, - db - .select({ id: siteResourceLabels.siteResourceId }) - .from(siteResourceLabels) - .innerJoin( - labels, - eq(labels.labelId, siteResourceLabels.labelId) - ) - .where(like(sql`LOWER(${labels.name})`, q)) - ) - ); - } - conditions.push(or(...queryList)); } @@ -403,7 +393,7 @@ export async function listAllSiteResourcesByOrg( siteResourceId: number; }> = []; - if (isLabelFeatureEnabled && siteResourceIdList.length > 0) { + if (siteResourceIdList.length > 0) { labelsForSiteResources = await db .select({ labelId: labels.labelId, diff --git a/src/app/[orgId]/settings/(private)/labels/page.tsx b/src/app/[orgId]/settings/labels/page.tsx similarity index 90% rename from src/app/[orgId]/settings/(private)/labels/page.tsx rename to src/app/[orgId]/settings/labels/page.tsx index f2ef0aa44..806c60325 100644 --- a/src/app/[orgId]/settings/(private)/labels/page.tsx +++ b/src/app/[orgId]/settings/labels/page.tsx @@ -3,9 +3,7 @@ import { authCookieHeader } from "@app/lib/api/cookies"; import { ListOrgLabelsResponse } from "@server/routers/labels/types"; import { AxiosResponse } from "axios"; import OrgLabelsTable from "@app/components/OrgLabelsTable"; -import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; -import { tierMatrix } from "@server/lib/billing/tierMatrix"; import type { Metadata } from "next"; import { getTranslations } from "next-intl/server"; @@ -51,8 +49,6 @@ export default async function LabelsPage({ params, searchParams }: Props) { description={t("orgLabelsDescription")} /> - - {t("address")} - } - ]; - - if (isLabelFeatureEnabled) { - baseColumns.push({ + }, + { id: "labels", accessorKey: "labels", header: () => ( @@ -458,8 +454,8 @@ export default function MachineClientsTable({ orgId={orgId} /> ) - }); - } + } + ]; // Only include actions column if there are rows without userIds if (hasRowsWithoutUserId) { @@ -541,7 +537,7 @@ export default function MachineClientsTable({ } return baseColumns; - }, [hasRowsWithoutUserId, isLabelFeatureEnabled, orgId, t, searchParams]); + }, [hasRowsWithoutUserId, orgId, t, searchParams]); function handleFilterChange( column: string, diff --git a/src/components/OrgLabelsTable.tsx b/src/components/OrgLabelsTable.tsx index 3b2ea691b..1d936f274 100644 --- a/src/components/OrgLabelsTable.tsx +++ b/src/components/OrgLabelsTable.tsx @@ -21,9 +21,6 @@ import { ControlledDataTable, type ExtendedColumnDef } from "./ui/controlled-data-table"; -import { LabelBadge } from "./label-badge"; -import { getNextSortOrder, getSortDirection } from "@app/lib/sortColumn"; -import { cn } from "@app/lib/cn"; import ConfirmDeleteDialog from "./ConfirmDeleteDialog"; import { CreateOrgLabelDialog } from "./CreateOrgLabelDialog"; import { EditOrgLabelDialog } from "./EditOrgLabelDialog"; diff --git a/src/components/PrivateResourcesTable.tsx b/src/components/PrivateResourcesTable.tsx index ff854a1a8..9d0de1036 100644 --- a/src/components/PrivateResourcesTable.tsx +++ b/src/components/PrivateResourcesTable.tsx @@ -151,7 +151,6 @@ export default function PrivateResourcesTable({ const [isRefreshing, startRefreshTransition] = useTransition(); const { isPaidUser } = usePaidStatus(); - const isLabelFeatureEnabled = isPaidUser(tierMatrix.labels); // useEffect(() => { // const interval = setInterval(() => { @@ -476,11 +475,8 @@ export default function PrivateResourcesTable({ ); } - } - ]; - - if (isLabelFeatureEnabled) { - cols.splice(cols.length - 1, 0, { + }, + { id: "labels", accessorKey: "labels", header: () => ( @@ -500,11 +496,11 @@ export default function PrivateResourcesTable({ orgId={orgId} /> ) - }); - } + } + ]; return cols; - }, [isLabelFeatureEnabled, orgId, t, searchParams]); + }, [orgId, t, searchParams]); function handleFilterChange( column: string, diff --git a/src/components/PublicResourcesTable.tsx b/src/components/PublicResourcesTable.tsx index 1cc13ad80..2ac60013a 100644 --- a/src/components/PublicResourcesTable.tsx +++ b/src/components/PublicResourcesTable.tsx @@ -151,7 +151,6 @@ export default function PublicResourcesTable({ useState(); const { isPaidUser } = usePaidStatus(); - const isLabelFeatureEnabled = isPaidUser(tierMatrix.labels); const [isRefreshing, startTransition] = useTransition(); const [isNavigatingToAddPage, startNavigation] = useTransition(); @@ -604,11 +603,8 @@ export default function PublicResourcesTable({ ); } - } - ]; - - if (isLabelFeatureEnabled) { - cols.splice(cols.length - 1, 0, { + }, + { id: "labels", accessorKey: "labels", header: () => ( @@ -625,11 +621,11 @@ export default function PublicResourcesTable({ cell: ({ row }: { row: { original: ResourceRow } }) => ( ) - }); - } + } + ]; return cols; - }, [isLabelFeatureEnabled, orgId, t, searchParams]); + }, [orgId, t, searchParams]); function handleFilterChange( column: string, diff --git a/src/components/SitesTable.tsx b/src/components/SitesTable.tsx index efcf83e72..2592a2143 100644 --- a/src/components/SitesTable.tsx +++ b/src/components/SitesTable.tsx @@ -53,7 +53,6 @@ import { import { useOptimisticLabels } from "@app/hooks/useOptimisticLabels"; import { usePaidStatus } from "@app/hooks/usePaidStatus"; -import { tierMatrix } from "@server/lib/billing/tierMatrix"; import { LabelColumnFilterButton } from "./LabelColumnFilterButton"; import { LabelsTableCell } from "./LabelsTableCell"; import { useQuery } from "@tanstack/react-query"; @@ -114,7 +113,6 @@ export default function SitesTable({ const [isNavigatingToAddPage, startNavigation] = useTransition(); const { isPaidUser } = usePaidStatus(); - const isLabelFeatureEnabled = isPaidUser(tierMatrix.labels); const api = createApiClient(useEnvContext()); const t = useTranslations(); @@ -171,7 +169,10 @@ export default function SitesTable({ toast({ variant: "destructive", title: t("siteErrorRestart"), - description: formatAxiosError(e, t("siteErrorRestartDescription")) + description: formatAxiosError( + e, + t("siteErrorRestartDescription") + ) }); } finally { setRestartingSite(null); @@ -598,11 +599,8 @@ export default function SitesTable({ ); } - } - ]; - - if (isLabelFeatureEnabled) { - cols.splice(cols.length - 1, 0, { + }, + { accessorKey: "labels", header: () => ( ( ) - }); - } + } + ]; return cols; - }, [isLabelFeatureEnabled, orgId, t, searchParams, latestNewtVersion]); + }, [orgId, t, searchParams, latestNewtVersion]); function toggleSort(column: string) { const newSearch = getNextSortOrder(column, searchParams);