diff --git a/.docker/Dockerfile b/.docker/Dockerfile index d7fb992e5aa..1d27885cfc0 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -79,17 +79,13 @@ COPY ghost/email-service/package.json ghost/email-service/package.json COPY ghost/html-to-plaintext/package.json ghost/html-to-plaintext/package.json COPY ghost/i18n/package.json ghost/i18n/package.json COPY ghost/job-manager/package.json ghost/job-manager/package.json -COPY ghost/link-replacer/package.json ghost/link-replacer/package.json -COPY ghost/member-attribution/package.json ghost/member-attribution/package.json COPY ghost/members-csv/package.json ghost/members-csv/package.json COPY ghost/mw-error-handler/package.json ghost/mw-error-handler/package.json COPY ghost/mw-vhost/package.json ghost/mw-vhost/package.json -COPY ghost/offers/package.json ghost/offers/package.json COPY ghost/post-events/package.json ghost/post-events/package.json COPY ghost/post-revisions/package.json ghost/post-revisions/package.json COPY ghost/prometheus-metrics/package.json ghost/prometheus-metrics/package.json COPY ghost/security/package.json ghost/security/package.json -COPY ghost/tiers/package.json ghost/tiers/package.json COPY ghost/webmentions/package.json ghost/webmentions/package.json ## Install dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba5b56920de..89c79744233 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -486,7 +486,7 @@ jobs: - run: yarn nx affected -t test:unit --base=${{ needs.job_setup.outputs.BASE_COMMIT }} - uses: actions/upload-artifact@v4 - if: startsWith(matrix.node, '18') + if: startsWith(matrix.node, '20') with: name: unit-coverage path: ghost/*/coverage/cobertura-coverage.xml @@ -582,7 +582,7 @@ jobs: echo "test_time=$(($endTime-$startTime))" >> $GITHUB_ENV - uses: actions/upload-artifact@v4 - if: startsWith(matrix.node, '18') && contains(matrix.env.DB, 'mysql') + if: startsWith(matrix.node, '20') && contains(matrix.env.DB, 'mysql') with: name: e2e-coverage path: | diff --git a/apps/admin-x-activitypub/src/api/activitypub.ts b/apps/admin-x-activitypub/src/api/activitypub.ts index 511571f4927..f9b8a3f2ef0 100644 --- a/apps/admin-x-activitypub/src/api/activitypub.ts +++ b/apps/admin-x-activitypub/src/api/activitypub.ts @@ -23,6 +23,7 @@ export interface Account { followsMe: boolean; followedByMe: boolean; blockedByMe: boolean; + domainBlockedByMe: boolean; attachment: { name: string; value: string }[]; } @@ -202,6 +203,24 @@ export class ActivityPubAPI { return json; } + async blockDomain(domain: URL): Promise { + const url = new URL( + `.ghost/activitypub/actions/block/domain/${encodeURIComponent(domain.href)}`, + this.apiUrl + ); + await this.fetchJSON(url, 'POST'); + return true; + } + + async unblockDomain(domain: URL): Promise { + const url = new URL( + `.ghost/activitypub/actions/unblock/domain/${encodeURIComponent(domain.href)}`, + this.apiUrl + ); + await this.fetchJSON(url, 'POST'); + return true; + } + async block(id: URL): Promise { const url = new URL( `.ghost/activitypub/actions/block/${encodeURIComponent(id.href)}`, diff --git a/apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts b/apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts index 82d06dd5f2a..d8a16db318d 100644 --- a/apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts +++ b/apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts @@ -300,6 +300,62 @@ export function useUnlikeMutationForUser(handle: string) { }); } +export function useBlockDomainMutationForUser(handle: string) { + const queryClient = useQueryClient(); + + return useMutation({ + async mutationFn(account: Account) { + const siteUrl = await getSiteUrl(); + const api = createActivityPubAPI(handle, siteUrl); + + return api.blockDomain(new URL(account.apId)); + }, + onMutate: (account: Account) => { + queryClient.setQueryData( + QUERY_KEYS.account(account.handle), + (currentAccount?: Account) => { + if (!currentAccount) { + return currentAccount; + } + return { + ...currentAccount, + domainBlockedByMe: true, + followedByMe: false, + followsMe: false + }; + } + ); + } + }); +} + +export function useUnblockDomainMutationForUser(handle: string) { + const queryClient = useQueryClient(); + + return useMutation({ + async mutationFn(account: Account) { + const siteUrl = await getSiteUrl(); + const api = createActivityPubAPI(handle, siteUrl); + + return api.unblockDomain(new URL(account.apId)); + }, + onMutate: (account: Account) => { + queryClient.setQueryData( + QUERY_KEYS.account(account.handle), + (currentAccount?: Account) => { + if (!currentAccount) { + return currentAccount; + } + return { + ...currentAccount, + domainBlockedByMe: false + }; + } + ); + } + }); +} + export function useBlockMutationForUser(handle: string) { const queryClient = useQueryClient(); diff --git a/apps/admin-x-framework/src/api/newsletters.ts b/apps/admin-x-framework/src/api/newsletters.ts index 6f045ea7dc2..4a6964c657c 100644 --- a/apps/admin-x-framework/src/api/newsletters.ts +++ b/apps/admin-x-framework/src/api/newsletters.ts @@ -40,6 +40,7 @@ export type Newsletter = { divider_color: string | null; button_corners: string | null; button_style: string | null; + image_corners: string | null; link_style: string | null; divider_style: string | null; created_at: string; diff --git a/apps/admin-x-framework/src/api/stats.ts b/apps/admin-x-framework/src/api/stats.ts index e1a23bd3166..104253bba5d 100644 --- a/apps/admin-x-framework/src/api/stats.ts +++ b/apps/admin-x-framework/src/api/stats.ts @@ -60,12 +60,38 @@ export type PostReferrersResponseType = { meta: Meta; }; +export type PostGrowthStatItem = { + post_id: string; + free_members: number; + paid_members: number; + mrr: number; +}; + +export type PostGrowthStatsResponseType = { + stats: PostGrowthStatItem[]; + meta: Meta; +}; + +export type MrrHistoryItem = { + date: string; + mrr: number; + currency: string; +}; +export type MrrHistoryResponseType = { + stats: MrrHistoryItem[]; + meta: Meta; +}; + // Requests const dataType = 'TopContentResponseType'; const memberCountHistoryDataType = 'MemberCountHistoryResponseType'; const topPostsStatsDataType = 'TopPostsStatsResponseType'; const postReferrersDataType = 'PostReferrersResponseType'; + +const postGrowthStatsDataType = 'PostGrowthStatsResponseType'; +const mrrHistoryDataType = 'MrrHistoryResponseType'; + export const useTopContent = createQuery({ dataType, path: '/stats/top-content/' @@ -85,3 +111,12 @@ export const usePostReferrers = createQueryWithId({ dataType: postReferrersDataType, path: id => `/stats/posts/${id}/top-referrers` }); + +export const usePostGrowthStats = createQueryWithId({ + dataType: postGrowthStatsDataType, + path: id => `/stats/posts/${id}/growth` +}); +export const useMrrHistory = createQuery({ + dataType: mrrHistoryDataType, + path: '/stats/mrr/' +}); diff --git a/apps/admin-x-framework/src/test/responses/newsletters.json b/apps/admin-x-framework/src/test/responses/newsletters.json index 3988255017e..19904fcce69 100644 --- a/apps/admin-x-framework/src/test/responses/newsletters.json +++ b/apps/admin-x-framework/src/test/responses/newsletters.json @@ -35,6 +35,7 @@ "button_color": null, "button_style": "fill", "button_corners": null, + "image_corners": null, "link_color": null, "link_style": null, "divider_style": null, @@ -81,6 +82,7 @@ "button_color": null, "button_style": "fill", "button_corners": null, + "image_corners": null, "link_color": null, "link_style": null, "divider_style": null, diff --git a/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx b/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx index 18c9387c93b..cbdc5983252 100644 --- a/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx +++ b/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterDetailModalLabs.tsx @@ -94,6 +94,8 @@ const Sidebar: React.FC<{ const fontWeightOptions: SelectOption[] = [ {value: 'normal', label: 'Normal'}, + {value: 'medium', label: 'Medium'}, + {value: 'semibold', label: 'Semi-bold'}, {value: 'bold', label: 'Bold'} ]; @@ -603,6 +605,31 @@ const Sidebar: React.FC<{ } ]} clearBg={false} /> +
+
Image corners
+ updateNewsletter({image_corners: 'square'}) + }, + { + key: 'squircle', + icon: 'squircle', + label: 'Squircle', + tooltip: 'Rounded', + hideLabel: true, + link: false, + size: 'sm', + onClick: () => updateNewsletter({image_corners: 'squircle'}) + } + ]} clearBg={false} /> +
Link style
= ({newsletter}) => headerImage={newsletter.header_image} headerSubtitle={headerSubtitle} headerTitle={headerTitle} + imageCorners={newsletter.image_corners || 'square'} linkStyle={newsletter.link_style || 'underline'} senderEmail={renderSenderEmail(newsletter, config, defaultEmailAddress)} senderName={newsletter.sender_name || title} diff --git a/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterPreviewContent.tsx b/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterPreviewContent.tsx index 5b70adf0b07..7e70cc63e19 100644 --- a/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterPreviewContent.tsx +++ b/apps/admin-x-settings/src/components/settings/email/newsletters/NewsletterPreviewContent.tsx @@ -46,6 +46,7 @@ const NewsletterPreviewContent: React.FC<{ linkColor?: string; buttonStyle?: string; buttonCorners?: string; + imageCorners?: string; linkStyle?: string; dividerStyle?: string; }> = ({ @@ -84,6 +85,7 @@ const NewsletterPreviewContent: React.FC<{ linkColor, buttonCorners, buttonStyle, + imageCorners, linkStyle, dividerStyle }) => { @@ -166,12 +168,13 @@ const NewsletterPreviewContent: React.FC<{

- Delivery Apps Are Changing Your Neighbourhood -

+ )} style={{color: titleColor}}>Delivery Apps Are Changing Your Neighbourhood {showExcerpt && (

Delivery apps are thriving—local restaurants and workers are paying the price.

)} @@ -211,7 +214,11 @@ const NewsletterPreviewContent: React.FC<{ 'h-[300px] w-full max-w-[600px] bg-cover bg-no-repeat', showPostTitleSection ? '' : 'pt-6' )}> - Feature + Feature
Feature image caption
@@ -257,10 +264,30 @@ const NewsletterPreviewContent: React.FC<{

Yet, the convenience factor keeps us coming back. The ease of one-click ordering means fewer people are dining in, changing the social fabric of our communities. Restaurants designed for shared experiences are evolving into ghost kitchens, optimized for delivery rather than connection.

-

When Convenience Comes at a Cost

+

When Convenience Comes at a Cost

So, what’s the future of food culture in an on-demand world? Can these platforms adapt to better support small businesses and workers? Or will we wake up one day to find that the places we once loved have vanished?

Some cities are beginning to push back. In San Francisco, legislation has been proposed to cap delivery app fees and ensure a fairer share of profits for restaurants. Other local governments are exploring ways to offer support to brick-and-mortar establishments, whether through grants, tax relief, or public campaigns that encourage residents to dine in more often.

-

Reimagining How We Eat

+

Reimagining How We Eat

Consumers are also starting to pay more attention. There's a growing movement toward mindful eating—not just in terms of ingredients, but in how we support the systems that bring food to our tables. Choosing to pick up instead of ordering in, tipping delivery drivers fairly, or subscribing to local restaurant coalitions can all make a difference.

Ultimately, the story of delivery apps isn’t just about technology or convenience—it’s about the kind of communities we want to live in. And that future depends, in part, on the choices we make every day.

@@ -308,32 +335,66 @@ const NewsletterPreviewContent: React.FC<{ {/* Latest posts */} {showLatestPosts && (
-

Keep reading

+

Keep reading

-

The three latest posts published on your site

+

The three latest posts published on your site

Posts sent as an email only will never be shown here.

-
- Latest post +
+ Latest post
-

Displayed at the bottom of each newsletter

+

Displayed at the bottom of each newsletter

Giving your readers one more place to discover your stories.

-
- Latest post +
+ Latest post
-

To keep your work front and center

+

To keep your work front and center

Making sure that your audience stays engaged.

-
- Latest post +
+ Latest post
@@ -342,7 +403,7 @@ const NewsletterPreviewContent: React.FC<{ {/* Subscription details */} {showSubscriptionDetails && (
-

Subscription details

+

Subscription details

You are receiving this because you are a paid subscriber to {siteTitle}. Your subscription will renew on 17 Jul 2024.

diff --git a/apps/posts/src/hooks/usePostReferrers.ts b/apps/posts/src/hooks/usePostReferrers.ts index c6b78bdffe4..b09b4792eb3 100644 --- a/apps/posts/src/hooks/usePostReferrers.ts +++ b/apps/posts/src/hooks/usePostReferrers.ts @@ -1,12 +1,28 @@ import {useMemo} from 'react'; -import {usePostReferrers as usePostReferrersAPI} from '@tryghost/admin-x-framework/api/stats'; +import {usePostGrowthStats as usePostGrowthStatsAPI, usePostReferrers as usePostReferrersAPI} from '@tryghost/admin-x-framework/api/stats'; export const usePostReferrers = (postId: string) => { - const {data: postReferrerResponse, isLoading} = usePostReferrersAPI(postId); + const {data: postReferrerResponse, isLoading: isPostReferrersLoading} = usePostReferrersAPI(postId); + const {data: postGrowthStatsResponse, isLoading: isPostGrowthStatsLoading} = usePostGrowthStatsAPI(postId); + const stats = useMemo(() => postReferrerResponse?.stats || [], [postReferrerResponse]); + const totals = useMemo(() => { + if (postGrowthStatsResponse?.stats.length === 0) { + return { + free_members: 0, + paid_members: 0, + mrr: 0 + }; + } else { + return postGrowthStatsResponse?.stats[0]; + } + }, [postGrowthStatsResponse]); + + const isLoading = useMemo(() => isPostReferrersLoading || isPostGrowthStatsLoading, [isPostReferrersLoading, isPostGrowthStatsLoading]); return { isLoading, - stats + stats, + totals }; }; diff --git a/apps/posts/src/views/PostAnalytics/Growth.tsx b/apps/posts/src/views/PostAnalytics/Growth.tsx index cc6d954cb19..276111b6fd3 100644 --- a/apps/posts/src/views/PostAnalytics/Growth.tsx +++ b/apps/posts/src/views/PostAnalytics/Growth.tsx @@ -13,7 +13,8 @@ interface postAnalyticsProps {} const Growth: React.FC = () => { // const {isLoading: isConfigLoading} = useGlobalData(); const {postId} = useParams(); - const {stats: postReferrers, isLoading} = usePostReferrers(postId || ''); + const {stats: postReferrers, totals, isLoading} = usePostReferrers(postId || ''); + // const {range} = useGlobalData(); return ( @@ -33,21 +34,21 @@ const Growth: React.FC = () => { Free members - {formatNumber(22)} + {formatNumber(totals?.free_members || 0)} Paid members - {formatNumber(8)} + {formatNumber(totals?.paid_members || 0)} MRR - +${formatNumber(180)} + +${formatNumber(totals?.mrr || 0)}
diff --git a/apps/posts/src/views/PostAnalytics/components/Web/Kpis.tsx b/apps/posts/src/views/PostAnalytics/components/Web/Kpis.tsx index cc33e15f997..7c6fac6e69a 100644 --- a/apps/posts/src/views/PostAnalytics/components/Web/Kpis.tsx +++ b/apps/posts/src/views/PostAnalytics/components/Web/Kpis.tsx @@ -180,7 +180,7 @@ const Kpis:React.FC = ({queryParams}) => { : -
+
} diff --git a/apps/stats/src/hooks/useGrowthStats.ts b/apps/stats/src/hooks/useGrowthStats.ts index edee7d91ba3..4f114c28699 100644 --- a/apps/stats/src/hooks/useGrowthStats.ts +++ b/apps/stats/src/hooks/useGrowthStats.ts @@ -1,5 +1,5 @@ import moment from 'moment'; -import {MemberStatusItem, useMemberCountHistory} from '@tryghost/admin-x-framework/api/stats'; +import {MemberStatusItem, MrrHistoryItem, useMemberCountHistory, useMrrHistory} from '@tryghost/admin-x-framework/api/stats'; import {formatNumber} from '@tryghost/shade'; import {useMemo} from 'react'; @@ -8,10 +8,10 @@ export type DiffDirection = 'up' | 'down' | 'same'; // Helper function to convert range to date parameters export const getRangeDates = (rangeInDays: number) => { - // Always use UTC to stay aligned with the backend’s date arithmetic + // Always use UTC to stay aligned with the backend's date arithmetic const endDate = moment.utc().format('YYYY-MM-DD'); let dateFrom; - + if (rangeInDays === 1) { // Today dateFrom = endDate; @@ -24,106 +24,163 @@ export const getRangeDates = (rangeInDays: number) => { const safeRange = Math.max(1, rangeInDays); dateFrom = moment.utc().subtract(safeRange - 1, 'days').format('YYYY-MM-DD'); } - + return {dateFrom, endDate}; }; // Calculate totals from member data -const calculateTotals = (memberData: MemberStatusItem[]) => { +const calculateTotals = (memberData: MemberStatusItem[], mrrData: MrrHistoryItem[]) => { if (!memberData.length) { return { totalMembers: 0, freeMembers: 0, paidMembers: 0, + mrr: 0, percentChanges: { total: '0%', free: '0%', - paid: '0%' + paid: '0%', + mrr: '0%' }, directions: { total: 'same' as DiffDirection, free: 'same' as DiffDirection, - paid: 'same' as DiffDirection + paid: 'same' as DiffDirection, + mrr: 'same' as DiffDirection } }; } - + // Get latest values - const latest = memberData[memberData.length - 1]; - + const latest = memberData.length > 0 ? memberData[memberData.length - 1] : {free: 0, paid: 0, comped: 0}; + + const latestMrr = mrrData.length > 0 ? mrrData[mrrData.length - 1] : {mrr: 0}; + // Calculate total members const totalMembers = latest.free + latest.paid + latest.comped; - + + const totalMrr = latestMrr.mrr; + // Calculate percentage changes if we have enough data const percentChanges = { total: '0%', free: '0%', - paid: '0%' + paid: '0%', + mrr: '0%' }; - + const directions = { total: 'same' as DiffDirection, free: 'same' as DiffDirection, - paid: 'same' as DiffDirection + paid: 'same' as DiffDirection, + mrr: 'same' as DiffDirection }; - + if (memberData.length > 1) { // Get first day in range const first = memberData[0]; const firstTotal = first.free + first.paid + first.comped; - + if (firstTotal > 0) { const totalChange = ((totalMembers - firstTotal) / firstTotal) * 100; percentChanges.total = `${Math.abs(totalChange).toFixed(1)}%`; directions.total = totalChange > 0 ? 'up' : totalChange < 0 ? 'down' : 'same'; } - + if (first.free > 0) { const freeChange = ((latest.free - first.free) / first.free) * 100; percentChanges.free = `${Math.abs(freeChange).toFixed(1)}%`; directions.free = freeChange > 0 ? 'up' : freeChange < 0 ? 'down' : 'same'; } - + if (first.paid > 0) { const paidChange = ((latest.paid - first.paid) / first.paid) * 100; percentChanges.paid = `${Math.abs(paidChange).toFixed(1)}%`; directions.paid = paidChange > 0 ? 'up' : paidChange < 0 ? 'down' : 'same'; } } - + + if (mrrData.length > 1) { + const first = mrrData[0]; + const firstMrr = first.mrr; + + if (firstMrr > 0) { + const mrrChange = ((totalMrr - firstMrr) / firstMrr) * 100; + percentChanges.mrr = `${Math.abs(mrrChange).toFixed(1)}%`; + directions.mrr = mrrChange > 0 ? 'up' : mrrChange < 0 ? 'down' : 'same'; + } + } + return { totalMembers, freeMembers: latest.free, paidMembers: latest.paid, + mrr: totalMrr, percentChanges, directions }; }; -// Format chart data -const formatChartData = (memberData: MemberStatusItem[]) => { - return memberData.map(item => ({ - date: item.date, - value: item.free + item.paid + item.comped, - free: item.free, - paid: item.paid, - comped: item.comped, - formattedValue: formatNumber(item.free + item.paid + item.comped), - label: 'Total members' - })); +// Format chart data +const formatChartData = (memberData: MemberStatusItem[], mrrData: MrrHistoryItem[]) => { + // Ensure data is sorted by date + const sortedMemberData = [...memberData].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); + const sortedMrrData = [...mrrData].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); + + const memberDates = sortedMemberData.map(item => item.date); + const mrrDates = sortedMrrData.map(item => item.date); + + const allDates = [...new Set([...memberDates, ...mrrDates])].sort((a, b) => new Date(a).getTime() - new Date(b).getTime()); + + let lastMemberItem: MemberStatusItem | null = null; + let lastMrrItem: MrrHistoryItem | null = null; + + const memberMap = new Map(sortedMemberData.map(item => [item.date, item])); + const mrrMap = new Map(sortedMrrData.map(item => [item.date, item])); + + return allDates.map((date) => { + const currentMemberItem = memberMap.get(date); + if (currentMemberItem) { + lastMemberItem = currentMemberItem; + } + + const currentMrrItem = mrrMap.get(date); + if (currentMrrItem) { + lastMrrItem = currentMrrItem; + } + + const free = lastMemberItem?.free ?? 0; + const paid = lastMemberItem?.paid ?? 0; + const comped = lastMemberItem?.comped ?? 0; + const value = free + paid + comped; + const mrr = lastMrrItem?.mrr ?? 0; + + return { + date, + value, + free, + paid, + comped, + mrr, + formattedValue: formatNumber(value), + label: 'Total members' // Consider if label needs update based on data type? + }; + }); }; export const useGrowthStats = (range: number) => { // Calculate date range const {dateFrom, endDate} = useMemo(() => getRangeDates(range), [range]); - + // Fetch member count history from API - const {data: memberCountResponse, isLoading} = useMemberCountHistory({ + const {data: memberCountResponse, isLoading: isMemberCountLoading} = useMemberCountHistory({ searchParams: { date_from: dateFrom } }); - + + const {data: mrrHistoryResponse, isLoading: isMrrLoading} = useMrrHistory(); + // Process member data with stable reference const memberData = useMemo(() => { // Check the structure of the response and extract data @@ -135,19 +192,33 @@ export const useGrowthStats = (range: number) => { } return []; }, [memberCountResponse]); - + + const mrrData = useMemo(() => { + // HACK: We should do this filtering on the backend, but the API doesn't support it yet + const dateFromMoment = moment(dateFrom).subtract(1, 'day'); + if (mrrHistoryResponse?.stats) { + return mrrHistoryResponse.stats.filter((item) => { + return moment(item.date).isSameOrAfter(dateFromMoment); + }); + } + return []; + }, [mrrHistoryResponse]); + // Calculate totals - const totalsData = useMemo(() => calculateTotals(memberData), [memberData]); - + const totalsData = useMemo(() => calculateTotals(memberData, mrrData), [memberData, mrrData]); + // Format chart data - const chartData = useMemo(() => formatChartData(memberData), [memberData]); - + const chartData = useMemo(() => formatChartData(memberData, mrrData), [memberData, mrrData]); + + const isLoading = useMemo(() => isMemberCountLoading || isMrrLoading, [isMemberCountLoading, isMrrLoading]); + return { isLoading, memberData, + mrrData, dateFrom, endDate, totals: totalsData, chartData }; -}; \ No newline at end of file +}; diff --git a/apps/stats/src/views/Stats/Growth.tsx b/apps/stats/src/views/Stats/Growth.tsx index 42bd311fa21..5bfc5bf5c59 100644 --- a/apps/stats/src/views/Stats/Growth.tsx +++ b/apps/stats/src/views/Stats/Growth.tsx @@ -5,15 +5,20 @@ import React, {useMemo, useState} from 'react'; import SortButton from './components/SortButton'; import StatsLayout from './layout/StatsLayout'; import StatsView from './layout/StatsView'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartTooltip, H1, Recharts, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, ViewHeader, ViewHeaderActions, formatDisplayDate, formatNumber} from '@tryghost/shade'; +import {Button, Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartTooltip, H1, Recharts, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, ViewHeader, ViewHeaderActions, formatDisplayDate, formatNumber} from '@tryghost/shade'; import {DiffDirection, useGrowthStats} from '@src/hooks/useGrowthStats'; import {KpiTabTrigger, KpiTabValue} from './components/KpiTab'; -import {Navigate} from '@tryghost/admin-x-framework'; +import {Navigate, useNavigate} from '@tryghost/admin-x-framework'; import {calculateYAxisWidth, getYRange, getYTicks, sanitizeChartData} from '@src/utils/chart-helpers'; import {getSettingValue} from '@tryghost/admin-x-framework/api/settings'; import {useGlobalData} from '@src/providers/GlobalDataProvider'; import {useTopPostsStatsWithRange} from '@src/hooks/useTopPostsStatsWithRange'; +// TODO: Move to @tryghost/shade +const centsToDollars = (value: number) => { + return Math.round(value / 100); +}; + type TopPostsOrder = 'free_members desc' | 'paid_members desc' | 'mrr desc'; type ChartDataItem = { @@ -22,6 +27,7 @@ type ChartDataItem = { free: number; paid: number; comped: number; + mrr: number; formattedValue: string; label?: string; }; @@ -30,15 +36,18 @@ type Totals = { totalMembers: number; freeMembers: number; paidMembers: number; + mrr: number; percentChanges: { total: string; free: string; paid: string; + mrr: string; }; directions: { total: DiffDirection; free: DiffDirection; paid: DiffDirection; + mrr: DiffDirection; }; }; @@ -50,7 +59,7 @@ const GrowthKPIs: React.FC<{ const {settings, range} = useGlobalData(); const labs = JSON.parse(getSettingValue(settings, 'labs') || '{}'); - const {totalMembers, freeMembers, paidMembers, percentChanges, directions} = totals; + const {totalMembers, freeMembers, paidMembers, mrr, percentChanges, directions} = totals; // Create chart data based on selected tab const chartData = useMemo(() => { @@ -70,22 +79,14 @@ const GrowthKPIs: React.FC<{ fieldName = 'paid'; break; case 'mrr': { - // TODO: replace the hard-coded 958 once real MRR is available - const avgMrrPerMember = paidMembers > 0 ? 958 / paidMembers : 0; - const mrrData = allChartData.map(item => ({ - ...item, - value: item.paid * avgMrrPerMember - })); - sanitizedData = sanitizeChartData(mrrData, range, 'value', 'exact'); + fieldName = 'mrr'; break; } default: fieldName = 'value'; } - if (currentTab !== 'mrr') { - sanitizedData = sanitizeChartData(allChartData, range, fieldName, 'exact'); - } + sanitizedData = sanitizeChartData(allChartData, range, fieldName, 'exact'); // Then map the sanitized data to the final format let processedData: ChartDataItem[] = []; @@ -110,7 +111,8 @@ const GrowthKPIs: React.FC<{ case 'mrr': processedData = sanitizedData.map(item => ({ ...item, - formattedValue: `$${item.value.toFixed(0)}`, + value: centsToDollars(item.mrr), + formattedValue: `$${formatNumber(centsToDollars(item.mrr))}`, label: 'MRR' })); break; @@ -124,7 +126,7 @@ const GrowthKPIs: React.FC<{ } return processedData; - }, [currentTab, allChartData, paidMembers, range]); + }, [currentTab, allChartData, range]); if (!labs.trafficAnalyticsAlpha) { return ; @@ -172,8 +174,12 @@ const GrowthKPIs: React.FC<{ { setCurrentTab('mrr'); }}> - {/* TODO: Add formatCurrency helper */} - +
@@ -260,6 +266,7 @@ const GrowthKPIs: React.FC<{ const Growth: React.FC = () => { const {range} = useGlobalData(); const [sortBy, setSortBy] = useState('free_members desc'); + const navigate = useNavigate(); // Get stats from custom hook once const {isLoading, chartData, totals} = useGrowthStats(range); @@ -316,7 +323,24 @@ const Growth: React.FC = () => { {topPosts.map(post => ( - {post.title} + +
+ {post.post_id ? + + : + <> + {post.title} + + } + {/* + + */} +
+
{(post.free_members > 0 && '+')}{formatNumber(post.free_members)} diff --git a/apps/stats/src/views/Stats/Web.tsx b/apps/stats/src/views/Stats/Web.tsx index 1654ed82225..ef20da868ac 100644 --- a/apps/stats/src/views/Stats/Web.tsx +++ b/apps/stats/src/views/Stats/Web.tsx @@ -5,13 +5,14 @@ import PostMenu from './components/PostMenu'; import React, {useState} from 'react'; import StatsLayout from './layout/StatsLayout'; import StatsView from './layout/StatsView'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartTooltip, H1, LucideIcon, Recharts, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, ViewHeader, ViewHeaderActions, formatDisplayDate, formatDuration, formatNumber, formatPercentage, formatQueryDate} from '@tryghost/shade'; +import {Button, Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartTooltip, H1, LucideIcon, Recharts, Separator, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, ViewHeader, ViewHeaderActions, formatDisplayDate, formatDuration, formatNumber, formatPercentage, formatQueryDate} from '@tryghost/shade'; import {KpiMetric} from '@src/types/kpi'; import {KpiTabTrigger, KpiTabValue} from './components/KpiTab'; import {TB_VERSION} from '@src/config/stats-config'; import {calculateYAxisWidth, getPeriodText, getRangeDates, getYTicks, sanitizeChartData} from '@src/utils/chart-helpers'; import {getStatEndpointUrl, getToken} from '@src/config/stats-config'; import {useGlobalData} from '@src/providers/GlobalDataProvider'; +import {useNavigate} from '@tryghost/admin-x-framework'; import {useQuery} from '@tinybirdco/charts'; import {useTopContent} from '@tryghost/admin-x-framework/api/stats'; @@ -224,6 +225,7 @@ const Web:React.FC = () => { const {isLoading: isConfigLoading} = useGlobalData(); const {range, audience} = useGlobalData(); const {startDate, endDate, timezone} = getRangeDates(range); + const navigate = useNavigate(); // Include essential query parameters that change frequently // Server will use defaults for other values @@ -284,10 +286,22 @@ const Web:React.FC = () => { return ( - - {row.title || row.pathname} - - +
+ {row.post_id ? + + : + <> + {row.title || row.pathname} + + } + + + +
{formatNumber(Number(row.visits))} diff --git a/compose.yml b/compose.yml index 5162209b9b9..292beb6bddf 100644 --- a/compose.yml +++ b/compose.yml @@ -19,17 +19,13 @@ x-service-template: &service-template - node_modules_ghost_html-to-plaintext:/home/ghost/ghost/html-to-plaintext/node_modules:delegated - node_modules_ghost_i18n:/home/ghost/ghost/i18n/node_modules:delegated - node_modules_ghost_job-manager:/home/ghost/ghost/job-manager/node_modules:delegated - - node_modules_ghost_link-replacer:/home/ghost/ghost/link-replacer/node_modules:delegated - - node_modules_ghost_member-attribution:/home/ghost/ghost/member-attribution/node_modules:delegated - node_modules_ghost_members-csv:/home/ghost/ghost/members-csv/node_modules:delegated - node_modules_ghost_mw-error-handler:/home/ghost/ghost/mw-error-handler/node_modules:delegated - node_modules_ghost_mw-vhost:/home/ghost/ghost/mw-vhost/node_modules:delegated - - node_modules_ghost_offers:/home/ghost/ghost/offers/node_modules:delegated - node_modules_ghost_post-events:/home/ghost/ghost/post-events/node_modules:delegated - node_modules_ghost_post-revisions:/home/ghost/ghost/post-revisions/node_modules:delegated - node_modules_ghost_prometheus-metrics:/home/ghost/ghost/prometheus-metrics/node_modules:delegated - node_modules_ghost_security:/home/ghost/ghost/security/node_modules:delegated - - node_modules_ghost_tiers:/home/ghost/ghost/tiers/node_modules:delegated - node_modules_ghost_webmentions:/home/ghost/ghost/webmentions/node_modules:delegated - node_modules_apps_admin-x-activitypub:/home/ghost/apps/admin-x-activitypub/node_modules:delegated - node_modules_apps_admin-x-design-system:/home/ghost/apps/admin-x-design-system/node_modules:delegated @@ -189,17 +185,13 @@ volumes: node_modules_ghost_html-to-plaintext: {} node_modules_ghost_i18n: {} node_modules_ghost_job-manager: {} - node_modules_ghost_link-replacer: {} - node_modules_ghost_member-attribution: {} node_modules_ghost_members-csv: {} node_modules_ghost_mw-error-handler: {} node_modules_ghost_mw-vhost: {} - node_modules_ghost_offers: {} node_modules_ghost_post-events: {} node_modules_ghost_post-revisions: {} node_modules_ghost_prometheus-metrics: {} node_modules_ghost_security: {} - node_modules_ghost_tiers: {} node_modules_ghost_webmentions: {} node_modules_apps_admin-x-activitypub: {} node_modules_apps_admin-x-design-system: {} diff --git a/ghost/admin/.lint-todo b/ghost/admin/.lint-todo index ee4ddb6bece..a6a909cd46f 100644 --- a/ghost/admin/.lint-todo +++ b/ghost/admin/.lint-todo @@ -1,565 +1,181 @@ -add|ember-template-lint|no-action|2|54|2|54|8618d17e29821f45d8809ad2d6cf6053b825f7fe|1728345600000|1738717200000|1743897600000|app/components/gh-billing-update-button.hbs -add|ember-template-lint|no-action|5|11|5|11|8eaebb48eca1563c6e0b18581df84ab59188d971|1728345600000|1738717200000|1743897600000|app/components/gh-cm-editor.hbs -add|ember-template-lint|no-passed-in-event-handlers|5|4|5|4|3a763e253744b070633bb8bd424b6c8e55f6b20a|1728345600000|1738717200000|1743897600000|app/components/gh-cm-editor.hbs -add|ember-template-lint|no-invalid-interactive|1|103|1|103|534029ab0ba1b74eff4a2f31c8b4dd9f1460316a|1728345600000|1738717200000|1743897600000|app/components/gh-context-menu.hbs -add|ember-template-lint|no-invalid-interactive|5|53|5|53|9647ef6afba919b2af04fe551b0fdf0fb63be849|1728345600000|1738717200000|1743897600000|app/components/gh-context-menu.hbs -add|ember-template-lint|no-action|5|18|5|18|0c80a75b2a80d404755333991c266c81c97c9cda|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|require-input-label|11|16|11|16|36ecd3af7ac0e4bbafbf933cc20ff9f3ff8f0947|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|require-input-label|29|8|29|8|334a3ea0fb16fabf58967294e125af8437504bdb|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|no-action|9|19|9|19|d12bcf1144bfb2fe70e7ab0f66836f1c6207a589|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|10|20|10|20|16d94650de2ffbe8ee3f2ce3ba5ca97a6304b739|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|11|17|11|17|30d64b1bf8990e2f84c52665690739fcc726e9f7|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|2|45|2|45|55b33496610b2f4ef6b9fe62713f4b4ddee37f19|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|10|29|10|29|ebbd89a393bcec7f537f2104ace2a6b1941a19a7|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|11|32|11|32|ab89b6f10c519be1271386203e9439d261eecd67|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|13|36|13|36|3776877637b49b65deef537c68ae490b2fb081a9|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-invalid-interactive|2|45|2|45|918fdec8490009c6197091e319d6ec52ee95b983|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|link-href-attributes|8|8|8|8|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|no-invalid-interactive|8|60|8|60|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|require-valid-alt-text|3|13|3|13|079fc89fa5c7c47f6b0b219820cdda3819c44e26|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|no-action|12|58|12|58|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|17|75|17|75|bbc5d9a459cd07e56d8c79dde619775b89d7cc89|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|22|52|22|52|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|31|16|31|16|4c64ddeaf795ee831d0d7346667a305814ca9855|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|32|15|32|15|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-invalid-interactive|22|52|22|52|74dea739bef284d6557987ff3da53fa1278030e2|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|10|16|10|16|8d8dd8c2cb5f9910c2de5ca6acc76ee4262a876e|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-mapping-input.hbs -add|ember-template-lint|no-action|9|36|9|36|05358b6ec6e9afbaa47416266c49f40a3ffb4490|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-table.hbs -add|ember-template-lint|no-action|10|36|10|36|c5ce93cf577ec47970f715ed83ed11a63adb7a63|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-table.hbs -add|ember-template-lint|no-action|8|50|8|50|de589665046a78748832e8f93d2e495d1d259265|1728345600000|1738717200000|1743897600000|app/components/gh-mobile-nav-bar.hbs -add|ember-template-lint|no-action|149|48|149|48|01f579966c325cf66d3a87799e8cea7dd1fded81|1728345600000|1738717200000|1743897600000|app/components/gh-portal-links.hbs -add|ember-template-lint|no-action|36|43|36|43|66cebfc8448eced0bccf3faa57b4af0cd633e65e|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|37|47|37|47|70f3e9aa9a9aa52142c4e0c015a8f173d12b05ed|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|56|41|56|41|43cc094c1a6b50ecd24c8af325dfdfcac863bb14|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|57|41|57|41|e7f429eefd04a55d4ef1875fe601da1b69964364|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|87|50|87|50|0e827c1770073f988535ceb9d6c49808a153d896|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|104|39|104|39|5cbc9d2abf29e108bfc207579df1206485e2a74d|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|105|43|105|43|1f2dd4961e9757ede9706bb0aa9b8baf9c49b22b|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|116|105|116|105|90dbb84741c72aa86a601e1cb95c066bd53898bd|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|123|46|123|46|56ca074eb0236b8becc4084423056a8ffa4453e9|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|158|73|158|73|b07bf9d50af5f00861571521b150cf6504b90704|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|172|56|172|56|38755451c044c56040684339301c21b2aab49ecb|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|190|50|190|50|9f1c3c88187e5db774f97704269e372f8331eba5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|196|50|196|50|97acfb2045b33a97621258596b631362ad4c56d5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|202|51|202|51|358336432fcb413c522c5f1ff3062a68ef9f449f|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|208|50|208|50|78a45cbb7eafdda134d96f6035b0026f339e75ad|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|214|50|214|50|693211baf08c011e77284b483c30e28ecaf63520|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|223|105|223|105|de5b68b49193c72f85c0e478f151a00180321d91|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|236|167|236|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|601|163|601|163|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|607|34|607|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|616|47|616|47|67551960e57b2ad06d24289e0d6f256dc5635cae|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|617|51|617|51|50e3029f4c845049ff10130cf0dc2ea06c7a3d2d|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|632|47|632|47|0d852775b4028d61c2c91b5d821c79de3cdbd1de|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|633|51|633|51|194439ec4cb10e176eecb1f55c2995c00f6c67b4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|647|47|647|47|3be93048908ab43d74726c3983982fcb9a3570e3|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|648|51|648|51|40871d259cc307345b8096e4215ae58e5886b724|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|674|166|674|166|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|681|34|681|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|686|44|686|44|d2abbb4bb55b6cb1131ca0bc56c31632b32b980c|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|687|44|687|44|3ede83bd64d206d665edb4f1b73f03b4122edfad|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|697|47|697|47|13b7064b520a924d9e57a4a680621ce979d23923|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|698|51|698|51|b0fc38b818f4ca2613684588e4122e12da0090b9|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|713|47|713|47|f34f084dc72c079be9ba3eb93c255bd8853612bd|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|714|51|714|51|c5c09d001fa96a623649cc88ef13b3c6c164f05b|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|742|167|742|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|748|34|748|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|753|44|753|44|32101c0834d9e8d2caa87dee9cb1a92fe633cfde|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|754|44|754|44|c8a82286cfe4220cb2d8a059b1daf7f6c8d54cf5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|764|47|764|47|31800fb83f1797de5d91b7007c48432cf2fae803|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|765|51|765|51|5ce0788874489341385f031810e9f7f62724aaf8|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|778|47|778|47|1cbd7d922a9d202772a9dca214d97bed18777d6e|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|779|51|779|51|16fb2c7c87dc282c6ee49a032aaaf22628b88084|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|810|168|810|168|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|816|34|816|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|823|50|823|50|d03e7bbf2b6de94b08fae1c33bd5a2f16874e03a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|825|48|825|48|bca167f0250b40d56ff1ed40ec21bc88f8e27ec3|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|836|50|836|50|93ae447fb1054de4dbe501fc60167a6ff3273687|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|838|48|838|48|ecb9ed2577be7ea0300563f22d8e9fde2fed12a6|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|36|36|36|36|fed655605208b290a18b9f7da51a6cf7b40c0e9a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|104|32|104|32|187e85e14470b453a1e6df8c5f18549d11c441a0|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|616|40|616|40|f290a04fd56f613d80d61244d161631f630185a8|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|632|40|632|40|c1af88109f705acc93fab4ee7b4d89096136ffe1|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|647|40|647|40|852cbb2c63e19a28d700d3b18e6f887edef303fa|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|697|40|697|40|58185c92e8b6261ea1483a70296d9fa837d3f2f5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|713|40|713|40|c4353acd715c396564c69389edd0a52246d3b966|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|764|40|764|40|29f26e46559dc40d9724a05b7516cb52f1481aaa|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|778|40|778|40|42e0617f832585eaa056c9c66dffe1a126318faf|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|823|40|823|40|d1dccfeee5b103fac3b14d5b4567bc65ee08fd5a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|836|40|836|40|055c4b70aa8daba6b97077eefa95ebed7f7f5315|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|4|14|4|14|c8f6146f9286ec1b289e28983ab446386f390f01|1728345600000|1738717200000|1743897600000|app/components/gh-psm-authors-input.hbs -add|ember-template-lint|no-action|6|14|6|14|3924d7cfb394cbcfd6b1bf9cf13a5040ac8f94b5|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|10|20|10|20|8b7921c0514cfd3fec8c3a474187048bc26faf7f|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|5|14|5|14|4168b695661f188460f6a14bdeecc8ce20b265e9|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|9|24|9|24|2e612be5e2b8e0b792f951c3c75b2f71df880365|1728345600000|1738717200000|1743897600000|app/components/gh-psm-template-select.hbs -add|ember-template-lint|no-action|7|16|7|16|86819b20fcc42bc1d4607519c1d45532ee337884|1728345600000|1738717200000|1743897600000|app/components/gh-psm-visibility-input.hbs -add|ember-template-lint|no-autofocus-attribute|13|16|13|16|fa0ffb960072633b72117849e3927673be0059af|1728345600000|1738717200000|1743897600000|app/components/gh-search-input.hbs -add|ember-template-lint|require-iframe-title|1|0|1|0|956ab219134ac63aec3fd2d35582076c21631b75|1728345600000|1738717200000|1743897600000|app/components/gh-site-iframe.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-text-input.hbs -add|ember-template-lint|no-action|1|51|1|51|674a942db62e014b25156b02d014f6c63b2f1cb2|1728345600000|1738717200000|1743897600000|app/components/gh-theme-error-li.hbs -add|ember-template-lint|no-action|2|11|2|11|2b1317e72b94ec31bf2700acc3f041e6be974b72|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|7|13|7|13|add4b57d48167f809045245535d45bedb00cb753|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|8|22|8|22|ce1eba2b791c0f120baf10871fd3949c1b9f6a79|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|9|22|9|22|0209f233628ec084b87894b4be9073c29f2a4f47|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -add|ember-template-lint|no-passed-in-event-handlers|4|4|4|4|3dedc53191768d81765eac4a7a049a9aba7df442|1728345600000|1738717200000|1743897600000|app/components/gh-url-input.hbs -add|ember-template-lint|no-action|1|71|1|71|2e6351f546807d88cc8eb9dbe8baa149468b5cb9|1728345600000|1738717200000|1743897600000|app/components/gh-view-title.hbs -add|ember-template-lint|no-invalid-role|1|0|1|0|3e651d38e0110e1be20e5082075db1b879b59a36|1728345600000|1738717200000|1743897600000|app/components/gh-view-title.hbs -add|ember-template-lint|no-action|5|50|5|50|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-impersonate-member.hbs -add|ember-template-lint|no-action|5|74|5|74|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-impersonate-member.hbs -add|ember-template-lint|no-action|43|57|43|57|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|50|56|50|56|190532b9954beb4e7e9e0f1c51d170e64d4a5315|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|56|34|56|34|ff609af61e9159dfc5386543d559f6d217d39531|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|57|29|57|29|9a0a72738b6e1a4f46415b2328c37d1814562717|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|110|89|110|89|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|116|91|116|91|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|119|116|119|116|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|129|120|129|120|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|132|103|132|103|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|143|112|143|112|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|147|110|147|110|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|153|97|153|97|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|156|112|156|112|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|160|99|160|99|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|163|110|163|110|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|171|91|171|91|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|174|102|174|102|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|181|95|181|95|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|185|102|185|102|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -add|ember-template-lint|no-invalid-interactive|28|24|28|24|42a29ae16e22270f0590c9ce5caa7bfec541ca0b|1728345600000|1738717200000|1743897600000|app/components/modal-member-tier.hbs -add|ember-template-lint|no-action|5|57|5|57|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|14|45|14|45|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|23|59|23|59|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|23|83|23|83|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|34|31|34|31|a8ad062b8379233b7970fe5ea74296fdf5011567|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|47|82|47|82|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|49|16|49|16|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|55|113|55|113|c259009ff744c2e9f7bb273e0eb3a3879036ba85|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|4|53|4|53|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|no-action|50|89|50|89|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|no-action|54|71|54|71|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|require-valid-alt-text|4|12|4|12|8369d1b06deac93e8c8e05444670c15182aea434|1728345600000|1738717200000|1743897600000|app/templates/application-error.hbs -add|ember-template-lint|no-passed-in-event-handlers|41|36|41|36|55f7b92a44dc897758496ba1560e34a1d53fb946|1728345600000|1738717200000|1743897600000|app/templates/offer.hbs -add|ember-template-lint|no-passed-in-event-handlers|205|52|205|52|eb97a902a644abbe2df5bc2e57f7affa0a96fdac|1728345600000|1738717200000|1743897600000|app/templates/offer.hbs -add|ember-template-lint|no-passed-in-event-handlers|227|40|227|40|5c7497369e17fd561d43dd7edad9c0887c21e9ff|1728345600000|1738717200000|1743897600000|app/templates/offer.hbs -add|ember-template-lint|no-passed-in-event-handlers|241|40|241|40|f6273c4d79a992751e950f5793ddf17bcf03e649|1728345600000|1738717200000|1743897600000|app/templates/offer.hbs -add|ember-template-lint|no-passed-in-event-handlers|256|36|256|36|5257e566aba16d7d9a28cf1df37a625c1eebfb25|1728345600000|1738717200000|1743897600000|app/templates/offer.hbs -add|ember-template-lint|no-action|20|31|20|31|3aa834e53af871a821ebb1b47f7a04f925c2b593|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|21|35|21|35|ae65e93ed2b79a307e0eba50b154fe84ee1ae210|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|37|31|37|31|eefdee43411bdd45c2786b9e826e6b550fd6212d|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|38|35|38|35|a8e4bd4c57a8f2df65749b0cfa4349da22b2a0aa|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|55|31|55|31|1709109776bf3fc47aaecc21e6d3ec8a0489ad6b|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|56|35|56|35|8000241a81189d3876d264331ec0c9b6476df076|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|73|31|73|31|6756e119daad4aa143724e9b56a6aef744d65251|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|74|35|74|35|26b1d89c0e5bbcd629a215903c0819d35f798aa6|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|20|24|20|24|f0b7babba7593639d68dadae2f19e7144dd8c63e|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|37|24|37|24|2692530760cb1f7156dcf9570aacf0f8baca2770|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|55|24|55|24|ce0d7e2e732b22ce3643fb9b1ac6ecef07c275ff|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|73|24|73|24|80681fcec2258c3d81a231bbd635aa1f03ff1452|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -add|ember-template-lint|no-action|6|108|6|108|ccc38f66549f9baedaa3b9943ae6634ea8f99e69|1728345600000|1738717200000|1743897600000|app/templates/tags.hbs -add|ember-template-lint|no-action|7|110|7|110|c3819ce2b6989e8596be570ed0c9fb82b5012521|1728345600000|1738717200000|1743897600000|app/templates/tags.hbs -add|ember-template-lint|require-valid-alt-text|15|32|15|32|80c1ce6724481312363dc4e1db42bf28b41909f2|1728345600000|1738717200000|1743897600000|app/templates/whatsnew.hbs -add|ember-template-lint|no-action|113|83|113|83|40a33b8afd29e93eebeaccdb49d729c06f755e1f|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-invalid-interactive|113|83|113|83|91111b837d1217ec9988076f5263b0e32df72604|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|45|104|45|104|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|65|131|65|131|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|100|93|100|93|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|50|89|50|89|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|73|57|73|57|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|78|57|78|57|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|89|131|89|131|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-action|10|110|10|110|4bbb6ad1f623335866ac715f34f2ce9829b1d55b|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-action|31|30|31|30|8eee88dbd40609f8ddc00330f4a47b1d30c483f0|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-action|142|110|142|110|c8306856104d54d12e3db50acab26094d0793fb3|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-interactive|31|30|31|30|929269f70336deb9f640bc0b5d54a0bd5336d27a|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-link-title|27|24|27|24|17a357b69040eb9e19a79fe08468c698eab84939|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|27|51|27|51|b8aae2daed1c14cf280800b3d282d11fb14851a4|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|32|103|32|103|571c3d774ed33480f528b54b323b23bfd7148eee|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|56|118|56|118|b8aae2daed1c14cf280800b3d282d11fb14851a4|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-interactive|8|51|8|51|66a27dbed218d15e49e91c72a93215ad0d90f778|1728345600000|1738717200000|1743897600000|app/components/gh-power-select/trigger.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/label-token.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/tag-token.hbs -add|ember-template-lint|no-action|8|19|8|19|73ac7d3892fcbcf15c3d5c44fca14dd21016daea|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/trigger.hbs -add|ember-template-lint|no-positive-tabindex|46|8|46|8|6118264a9a0599fab6ad4da7264c1bfffa88687e|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/trigger.hbs -add|ember-template-lint|require-iframe-title|27|20|27|20|94e58d11848d5613900c2188ba63dac41f4c03bb|1728345600000|1738717200000|1743897600000|app/components/modals/email-preview.hbs -add|ember-template-lint|require-iframe-title|42|16|42|16|a3292b469dc37f2f4791e7f224b0b65c8ecf5d18|1728345600000|1738717200000|1743897600000|app/components/modals/email-preview.hbs -add|ember-template-lint|no-autofocus-attribute|21|20|21|20|942419d05c04ded6716f09faecd6b1ab55418121|1728345600000|1738717200000|1743897600000|app/components/modals/new-custom-integration.hbs -add|ember-template-lint|no-invalid-interactive|2|37|2|37|e21ba31f54b631a428c28a1c9f88d0dc66f2f5fc|1728345600000|1738717200000|1743897600000|app/components/modals/search.hbs -remove|ember-template-lint|no-action|5|14|5|14|4168b695661f188460f6a14bdeecc8ce20b265e9|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|73|76|73|76|7d339c0f3d02ec863651697ad8e8105158d858f1|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|5|14|5|14|88b11bf43be33d97824ebac071a563affac0b97d|1730678400000|1741046400000|1746230400000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|73|82|73|82|f30d469e4ae668f05aca2f92a124a6b4748847a3|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|73|76|73|76|7d339c0f3d02ec863651697ad8e8105158d858f1|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|5|14|5|14|a90edd9a99596008f60bfcdbc6befe7fe8d26321|1730678400000|1741046400000|1746230400000|app/components/gh-psm-tags-input.hbs -remove|ember-template-lint|no-action|5|14|5|14|88b11bf43be33d97824ebac071a563affac0b97d|1730678400000|1741046400000|1746230400000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|80|92|80|92|f30d469e4ae668f05aca2f92a124a6b4748847a3|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|8|50|8|50|de589665046a78748832e8f93d2e495d1d259265|1728345600000|1738717200000|1743897600000|app/components/gh-mobile-nav-bar.hbs -add|ember-template-lint|no-action|12|16|12|16|3696846a8a04d429559abebaaf5dab2c6387c21f|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-action|34|26|34|26|3b76c38861ddcdfaa277e272a1d27293c2659524|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-interactive|34|26|34|26|0c04fbca90264398b6b5033632f3170c73d1769b|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-link-title|29|20|29|20|593cda92786c7440169712eadac45a452b967dd5|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-action|10|110|10|110|4bbb6ad1f623335866ac715f34f2ce9829b1d55b|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-action|31|30|31|30|8eee88dbd40609f8ddc00330f4a47b1d30c483f0|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-invalid-interactive|31|30|31|30|929269f70336deb9f640bc0b5d54a0bd5336d27a|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-invalid-link-title|27|24|27|24|17a357b69040eb9e19a79fe08468c698eab84939|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-interactive|41|26|41|26|da9f7c0f319619ff98a53fd679c47841cfaa3c1d|1736380800000|1746745200000|1751929200000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-redundant-fn|5|70|5|70|d8c5269c9b4ca3aec0fc5b8e3d6a997e115dbc92|1736380800000|1746745200000|1751929200000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-invalid-interactive|34|26|34|26|0c04fbca90264398b6b5033632f3170c73d1769b|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-action|113|83|113|83|40a33b8afd29e93eebeaccdb49d729c06f755e1f|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|no-invalid-interactive|113|83|113|83|91111b837d1217ec9988076f5263b0e32df72604|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|no-invalid-link-title|29|20|29|20|593cda92786c7440169712eadac45a452b967dd5|1734307200000|1744671600000|1749855600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-action|2|54|2|54|8618d17e29821f45d8809ad2d6cf6053b825f7fe|1728345600000|1738717200000|1743897600000|app/components/gh-billing-update-button.hbs -remove|ember-template-lint|no-action|5|11|5|11|8eaebb48eca1563c6e0b18581df84ab59188d971|1728345600000|1738717200000|1743897600000|app/components/gh-cm-editor.hbs -remove|ember-template-lint|no-passed-in-event-handlers|5|4|5|4|3a763e253744b070633bb8bd424b6c8e55f6b20a|1728345600000|1738717200000|1743897600000|app/components/gh-cm-editor.hbs -remove|ember-template-lint|no-invalid-interactive|1|103|1|103|534029ab0ba1b74eff4a2f31c8b4dd9f1460316a|1728345600000|1738717200000|1743897600000|app/components/gh-context-menu.hbs -remove|ember-template-lint|no-invalid-interactive|5|53|5|53|9647ef6afba919b2af04fe551b0fdf0fb63be849|1728345600000|1738717200000|1743897600000|app/components/gh-context-menu.hbs -remove|ember-template-lint|no-action|5|18|5|18|0c80a75b2a80d404755333991c266c81c97c9cda|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -remove|ember-template-lint|require-input-label|11|16|11|16|36ecd3af7ac0e4bbafbf933cc20ff9f3ff8f0947|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -remove|ember-template-lint|require-input-label|29|8|29|8|334a3ea0fb16fabf58967294e125af8437504bdb|1728345600000|1738717200000|1743897600000|app/components/gh-date-time-picker.hbs -remove|ember-template-lint|no-action|9|19|9|19|d12bcf1144bfb2fe70e7ab0f66836f1c6207a589|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -remove|ember-template-lint|no-action|10|20|10|20|16d94650de2ffbe8ee3f2ce3ba5ca97a6304b739|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -remove|ember-template-lint|no-action|11|17|11|17|30d64b1bf8990e2f84c52665690739fcc726e9f7|1728345600000|1738717200000|1743897600000|app/components/gh-editor.hbs -remove|ember-template-lint|no-action|2|45|2|45|55b33496610b2f4ef6b9fe62713f4b4ddee37f19|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -remove|ember-template-lint|no-action|10|29|10|29|ebbd89a393bcec7f537f2104ace2a6b1941a19a7|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -remove|ember-template-lint|no-action|11|32|11|32|ab89b6f10c519be1271386203e9439d261eecd67|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -remove|ember-template-lint|no-action|13|36|13|36|3776877637b49b65deef537c68ae490b2fb081a9|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -remove|ember-template-lint|no-invalid-interactive|2|45|2|45|918fdec8490009c6197091e319d6ec52ee95b983|1728345600000|1738717200000|1743897600000|app/components/gh-fullscreen-modal.hbs -remove|ember-template-lint|link-href-attributes|8|8|8|8|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -remove|ember-template-lint|no-invalid-interactive|8|60|8|60|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -remove|ember-template-lint|require-valid-alt-text|3|13|3|13|079fc89fa5c7c47f6b0b219820cdda3819c44e26|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader-with-preview.hbs -remove|ember-template-lint|no-action|12|58|12|58|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-action|17|75|17|75|bbc5d9a459cd07e56d8c79dde619775b89d7cc89|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-action|22|52|22|52|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-action|31|16|31|16|4c64ddeaf795ee831d0d7346667a305814ca9855|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-action|32|15|32|15|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-invalid-interactive|22|52|22|52|74dea739bef284d6557987ff3da53fa1278030e2|1728345600000|1738717200000|1743897600000|app/components/gh-image-uploader.hbs -remove|ember-template-lint|no-action|10|16|10|16|8d8dd8c2cb5f9910c2de5ca6acc76ee4262a876e|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-mapping-input.hbs -remove|ember-template-lint|no-action|9|36|9|36|05358b6ec6e9afbaa47416266c49f40a3ffb4490|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-table.hbs -remove|ember-template-lint|no-action|10|36|10|36|c5ce93cf577ec47970f715ed83ed11a63adb7a63|1728345600000|1738717200000|1743897600000|app/components/gh-members-import-table.hbs -remove|ember-template-lint|no-action|36|43|36|43|66cebfc8448eced0bccf3faa57b4af0cd633e65e|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|37|47|37|47|70f3e9aa9a9aa52142c4e0c015a8f173d12b05ed|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|56|41|56|41|43cc094c1a6b50ecd24c8af325dfdfcac863bb14|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|57|41|57|41|e7f429eefd04a55d4ef1875fe601da1b69964364|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|87|50|87|50|0e827c1770073f988535ceb9d6c49808a153d896|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|104|39|104|39|5cbc9d2abf29e108bfc207579df1206485e2a74d|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|105|43|105|43|1f2dd4961e9757ede9706bb0aa9b8baf9c49b22b|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|123|46|123|46|56ca074eb0236b8becc4084423056a8ffa4453e9|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|158|73|158|73|b07bf9d50af5f00861571521b150cf6504b90704|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|172|56|172|56|38755451c044c56040684339301c21b2aab49ecb|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|190|50|190|50|9f1c3c88187e5db774f97704269e372f8331eba5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|196|50|196|50|97acfb2045b33a97621258596b631362ad4c56d5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|202|51|202|51|358336432fcb413c522c5f1ff3062a68ef9f449f|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|208|50|208|50|78a45cbb7eafdda134d96f6035b0026f339e75ad|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|214|50|214|50|693211baf08c011e77284b483c30e28ecaf63520|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|223|105|223|105|de5b68b49193c72f85c0e478f151a00180321d91|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|236|167|236|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|601|163|601|163|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|607|34|607|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|616|47|616|47|67551960e57b2ad06d24289e0d6f256dc5635cae|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|617|51|617|51|50e3029f4c845049ff10130cf0dc2ea06c7a3d2d|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|632|47|632|47|0d852775b4028d61c2c91b5d821c79de3cdbd1de|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|633|51|633|51|194439ec4cb10e176eecb1f55c2995c00f6c67b4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|647|47|647|47|3be93048908ab43d74726c3983982fcb9a3570e3|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|648|51|648|51|40871d259cc307345b8096e4215ae58e5886b724|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|674|166|674|166|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|681|34|681|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|686|44|686|44|d2abbb4bb55b6cb1131ca0bc56c31632b32b980c|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|687|44|687|44|3ede83bd64d206d665edb4f1b73f03b4122edfad|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|697|47|697|47|13b7064b520a924d9e57a4a680621ce979d23923|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|698|51|698|51|b0fc38b818f4ca2613684588e4122e12da0090b9|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|713|47|713|47|f34f084dc72c079be9ba3eb93c255bd8853612bd|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|714|51|714|51|c5c09d001fa96a623649cc88ef13b3c6c164f05b|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|742|167|742|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|748|34|748|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|753|44|753|44|32101c0834d9e8d2caa87dee9cb1a92fe633cfde|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|754|44|754|44|c8a82286cfe4220cb2d8a059b1daf7f6c8d54cf5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|764|47|764|47|31800fb83f1797de5d91b7007c48432cf2fae803|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|765|51|765|51|5ce0788874489341385f031810e9f7f62724aaf8|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|778|47|778|47|1cbd7d922a9d202772a9dca214d97bed18777d6e|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|779|51|779|51|16fb2c7c87dc282c6ee49a032aaaf22628b88084|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|810|168|810|168|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|816|34|816|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|823|50|823|50|d03e7bbf2b6de94b08fae1c33bd5a2f16874e03a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|825|48|825|48|bca167f0250b40d56ff1ed40ec21bc88f8e27ec3|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|836|50|836|50|93ae447fb1054de4dbe501fc60167a6ff3273687|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|838|48|838|48|ecb9ed2577be7ea0300563f22d8e9fde2fed12a6|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|36|36|36|36|fed655605208b290a18b9f7da51a6cf7b40c0e9a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|104|32|104|32|187e85e14470b453a1e6df8c5f18549d11c441a0|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|616|40|616|40|f290a04fd56f613d80d61244d161631f630185a8|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|632|40|632|40|c1af88109f705acc93fab4ee7b4d89096136ffe1|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|647|40|647|40|852cbb2c63e19a28d700d3b18e6f887edef303fa|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|697|40|697|40|58185c92e8b6261ea1483a70296d9fa837d3f2f5|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|713|40|713|40|c4353acd715c396564c69389edd0a52246d3b966|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|764|40|764|40|29f26e46559dc40d9724a05b7516cb52f1481aaa|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|778|40|778|40|42e0617f832585eaa056c9c66dffe1a126318faf|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|823|40|823|40|d1dccfeee5b103fac3b14d5b4567bc65ee08fd5a|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-passed-in-event-handlers|836|40|836|40|055c4b70aa8daba6b97077eefa95ebed7f7f5315|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|116|105|116|105|90dbb84741c72aa86a601e1cb95c066bd53898bd|1728345600000|1738717200000|1743897600000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|4|14|4|14|c8f6146f9286ec1b289e28983ab446386f390f01|1728345600000|1738717200000|1743897600000|app/components/gh-psm-authors-input.hbs -remove|ember-template-lint|no-action|6|14|6|14|3924d7cfb394cbcfd6b1bf9cf13a5040ac8f94b5|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -remove|ember-template-lint|no-action|10|20|10|20|8b7921c0514cfd3fec8c3a474187048bc26faf7f|1728345600000|1738717200000|1743897600000|app/components/gh-psm-tags-input.hbs -remove|ember-template-lint|no-action|9|24|9|24|2e612be5e2b8e0b792f951c3c75b2f71df880365|1728345600000|1738717200000|1743897600000|app/components/gh-psm-template-select.hbs -remove|ember-template-lint|no-action|7|16|7|16|86819b20fcc42bc1d4607519c1d45532ee337884|1728345600000|1738717200000|1743897600000|app/components/gh-psm-visibility-input.hbs -remove|ember-template-lint|no-autofocus-attribute|13|16|13|16|fa0ffb960072633b72117849e3927673be0059af|1728345600000|1738717200000|1743897600000|app/components/gh-search-input.hbs -remove|ember-template-lint|require-iframe-title|1|0|1|0|956ab219134ac63aec3fd2d35582076c21631b75|1728345600000|1738717200000|1743897600000|app/components/gh-site-iframe.hbs -remove|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-text-input.hbs -remove|ember-template-lint|no-action|1|51|1|51|674a942db62e014b25156b02d014f6c63b2f1cb2|1728345600000|1738717200000|1743897600000|app/components/gh-theme-error-li.hbs -remove|ember-template-lint|no-action|2|11|2|11|2b1317e72b94ec31bf2700acc3f041e6be974b72|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -remove|ember-template-lint|no-action|7|13|7|13|add4b57d48167f809045245535d45bedb00cb753|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -remove|ember-template-lint|no-action|8|22|8|22|ce1eba2b791c0f120baf10871fd3949c1b9f6a79|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -remove|ember-template-lint|no-action|9|22|9|22|0209f233628ec084b87894b4be9073c29f2a4f47|1728345600000|1738717200000|1743897600000|app/components/gh-uploader.hbs -remove|ember-template-lint|no-passed-in-event-handlers|4|4|4|4|3dedc53191768d81765eac4a7a049a9aba7df442|1728345600000|1738717200000|1743897600000|app/components/gh-url-input.hbs -remove|ember-template-lint|no-action|1|71|1|71|2e6351f546807d88cc8eb9dbe8baa149468b5cb9|1728345600000|1738717200000|1743897600000|app/components/gh-view-title.hbs -remove|ember-template-lint|no-invalid-role|1|0|1|0|3e651d38e0110e1be20e5082075db1b879b59a36|1728345600000|1738717200000|1743897600000|app/components/gh-view-title.hbs -remove|ember-template-lint|no-action|5|50|5|50|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-impersonate-member.hbs -remove|ember-template-lint|no-action|5|74|5|74|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-impersonate-member.hbs -remove|ember-template-lint|no-action|43|57|43|57|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|50|56|50|56|190532b9954beb4e7e9e0f1c51d170e64d4a5315|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|56|34|56|34|ff609af61e9159dfc5386543d559f6d217d39531|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|57|29|57|29|9a0a72738b6e1a4f46415b2328c37d1814562717|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|110|89|110|89|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|116|91|116|91|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|119|116|119|116|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|129|120|129|120|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|132|103|132|103|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|143|112|143|112|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|147|110|147|110|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|153|97|153|97|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|156|112|156|112|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|160|99|160|99|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|163|110|163|110|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|171|91|171|91|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|174|102|174|102|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|181|95|181|95|031d04576149d3034549aa3d14bc26da704cd70c|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-action|185|102|185|102|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-import-members.hbs -remove|ember-template-lint|no-invalid-interactive|28|24|28|24|42a29ae16e22270f0590c9ce5caa7bfec541ca0b|1728345600000|1738717200000|1743897600000|app/components/modal-member-tier.hbs -remove|ember-template-lint|no-action|5|57|5|57|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|14|45|14|45|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|23|59|23|59|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|23|83|23|83|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|34|31|34|31|a8ad062b8379233b7970fe5ea74296fdf5011567|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|47|82|47|82|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|49|16|49|16|d465b362b15b90cf42a093e72895155f49cdf6f2|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|55|113|55|113|c259009ff744c2e9f7bb273e0eb3a3879036ba85|1728345600000|1738717200000|1743897600000|app/components/modal-members-label-form.hbs -remove|ember-template-lint|no-action|4|53|4|53|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -remove|ember-template-lint|no-action|50|89|50|89|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -remove|ember-template-lint|no-action|54|71|54|71|141d456b03124abca146e58e4ae15825fdd040bb|1728345600000|1738717200000|1743897600000|app/components/modal-unsubscribe-members.hbs -remove|ember-template-lint|require-valid-alt-text|4|12|4|12|8369d1b06deac93e8c8e05444670c15182aea434|1728345600000|1738717200000|1743897600000|app/templates/application-error.hbs -remove|ember-template-lint|no-action|20|31|20|31|3aa834e53af871a821ebb1b47f7a04f925c2b593|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|21|35|21|35|ae65e93ed2b79a307e0eba50b154fe84ee1ae210|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|37|31|37|31|eefdee43411bdd45c2786b9e826e6b550fd6212d|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|38|35|38|35|a8e4bd4c57a8f2df65749b0cfa4349da22b2a0aa|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|55|31|55|31|1709109776bf3fc47aaecc21e6d3ec8a0489ad6b|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|56|35|56|35|8000241a81189d3876d264331ec0c9b6476df076|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|73|31|73|31|6756e119daad4aa143724e9b56a6aef744d65251|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|74|35|74|35|26b1d89c0e5bbcd629a215903c0819d35f798aa6|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-passed-in-event-handlers|20|24|20|24|f0b7babba7593639d68dadae2f19e7144dd8c63e|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-passed-in-event-handlers|37|24|37|24|2692530760cb1f7156dcf9570aacf0f8baca2770|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-passed-in-event-handlers|55|24|55|24|ce0d7e2e732b22ce3643fb9b1ac6ecef07c275ff|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-passed-in-event-handlers|73|24|73|24|80681fcec2258c3d81a231bbd635aa1f03ff1452|1728345600000|1738717200000|1743897600000|app/templates/setup.hbs -remove|ember-template-lint|no-action|6|108|6|108|ccc38f66549f9baedaa3b9943ae6634ea8f99e69|1728345600000|1738717200000|1743897600000|app/templates/tags.hbs -remove|ember-template-lint|no-action|7|110|7|110|c3819ce2b6989e8596be570ed0c9fb82b5012521|1728345600000|1738717200000|1743897600000|app/templates/tags.hbs -remove|ember-template-lint|require-valid-alt-text|15|32|15|32|80c1ce6724481312363dc4e1db42bf28b41909f2|1728345600000|1738717200000|1743897600000|app/templates/whatsnew.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|45|104|45|104|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|65|131|65|131|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|100|93|100|93|156670ca427c49c51f0a94f862b286ccc9466d92|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|require-context-role|50|89|50|89|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|require-context-role|73|57|73|57|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|require-context-role|78|57|78|57|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|require-context-role|89|131|89|131|0be75355d0dd43dafc60091285ba906c43350d19|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/footer.hbs -remove|ember-template-lint|no-action|142|110|142|110|c8306856104d54d12e3db50acab26094d0793fb3|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|27|51|27|51|b8aae2daed1c14cf280800b3d282d11fb14851a4|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|32|103|32|103|571c3d774ed33480f528b54b323b23bfd7148eee|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-unknown-arguments-for-builtin-components|56|118|56|118|b8aae2daed1c14cf280800b3d282d11fb14851a4|1728345600000|1738717200000|1743897600000|app/components/gh-nav-menu/main.hbs -remove|ember-template-lint|no-invalid-interactive|8|51|8|51|66a27dbed218d15e49e91c72a93215ad0d90f778|1728345600000|1738717200000|1743897600000|app/components/gh-power-select/trigger.hbs -remove|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/label-token.hbs -remove|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/tag-token.hbs -remove|ember-template-lint|no-action|8|19|8|19|73ac7d3892fcbcf15c3d5c44fca14dd21016daea|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/trigger.hbs -remove|ember-template-lint|no-positive-tabindex|46|8|46|8|6118264a9a0599fab6ad4da7264c1bfffa88687e|1728345600000|1738717200000|1743897600000|app/components/gh-token-input/trigger.hbs -remove|ember-template-lint|require-iframe-title|27|20|27|20|94e58d11848d5613900c2188ba63dac41f4c03bb|1728345600000|1738717200000|1743897600000|app/components/modals/email-preview.hbs -remove|ember-template-lint|require-iframe-title|42|16|42|16|a3292b469dc37f2f4791e7f224b0b65c8ecf5d18|1728345600000|1738717200000|1743897600000|app/components/modals/email-preview.hbs -remove|ember-template-lint|no-autofocus-attribute|21|20|21|20|942419d05c04ded6716f09faecd6b1ab55418121|1728345600000|1738717200000|1743897600000|app/components/modals/new-custom-integration.hbs -remove|ember-template-lint|no-invalid-interactive|2|37|2|37|e21ba31f54b631a428c28a1c9f88d0dc66f2f5fc|1728345600000|1738717200000|1743897600000|app/components/modals/search.hbs -add|ember-template-lint|no-action|2|54|2|54|8618d17e29821f45d8809ad2d6cf6053b825f7fe|1743984000000|1754352000000|1759536000000|app/components/gh-billing-update-button.hbs -add|ember-template-lint|no-action|5|11|5|11|8eaebb48eca1563c6e0b18581df84ab59188d971|1743984000000|1754352000000|1759536000000|app/components/gh-cm-editor.hbs -add|ember-template-lint|no-passed-in-event-handlers|5|4|5|4|3a763e253744b070633bb8bd424b6c8e55f6b20a|1743984000000|1754352000000|1759536000000|app/components/gh-cm-editor.hbs -add|ember-template-lint|no-invalid-interactive|1|103|1|103|534029ab0ba1b74eff4a2f31c8b4dd9f1460316a|1743984000000|1754352000000|1759536000000|app/components/gh-context-menu.hbs -add|ember-template-lint|no-invalid-interactive|5|53|5|53|9647ef6afba919b2af04fe551b0fdf0fb63be849|1743984000000|1754352000000|1759536000000|app/components/gh-context-menu.hbs -add|ember-template-lint|no-action|5|18|5|18|0c80a75b2a80d404755333991c266c81c97c9cda|1743984000000|1754352000000|1759536000000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|require-input-label|11|16|11|16|36ecd3af7ac0e4bbafbf933cc20ff9f3ff8f0947|1743984000000|1754352000000|1759536000000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|require-input-label|29|8|29|8|334a3ea0fb16fabf58967294e125af8437504bdb|1743984000000|1754352000000|1759536000000|app/components/gh-date-time-picker.hbs -add|ember-template-lint|no-action|9|19|9|19|d12bcf1144bfb2fe70e7ab0f66836f1c6207a589|1743984000000|1754352000000|1759536000000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|10|20|10|20|16d94650de2ffbe8ee3f2ce3ba5ca97a6304b739|1743984000000|1754352000000|1759536000000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|11|17|11|17|30d64b1bf8990e2f84c52665690739fcc726e9f7|1743984000000|1754352000000|1759536000000|app/components/gh-editor.hbs -add|ember-template-lint|no-action|2|45|2|45|55b33496610b2f4ef6b9fe62713f4b4ddee37f19|1743984000000|1754352000000|1759536000000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|10|29|10|29|ebbd89a393bcec7f537f2104ace2a6b1941a19a7|1743984000000|1754352000000|1759536000000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|11|32|11|32|ab89b6f10c519be1271386203e9439d261eecd67|1743984000000|1754352000000|1759536000000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-action|13|36|13|36|3776877637b49b65deef537c68ae490b2fb081a9|1743984000000|1754352000000|1759536000000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|no-invalid-interactive|2|45|2|45|918fdec8490009c6197091e319d6ec52ee95b983|1743984000000|1754352000000|1759536000000|app/components/gh-fullscreen-modal.hbs -add|ember-template-lint|link-href-attributes|8|8|8|8|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|no-invalid-interactive|8|60|8|60|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|require-valid-alt-text|3|13|3|13|079fc89fa5c7c47f6b0b219820cdda3819c44e26|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader-with-preview.hbs -add|ember-template-lint|no-action|12|58|12|58|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|17|75|17|75|bbc5d9a459cd07e56d8c79dde619775b89d7cc89|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|22|52|22|52|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|31|16|31|16|4c64ddeaf795ee831d0d7346667a305814ca9855|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|32|15|32|15|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-invalid-interactive|22|52|22|52|74dea739bef284d6557987ff3da53fa1278030e2|1743984000000|1754352000000|1759536000000|app/components/gh-image-uploader.hbs -add|ember-template-lint|no-action|10|16|10|16|8d8dd8c2cb5f9910c2de5ca6acc76ee4262a876e|1743984000000|1754352000000|1759536000000|app/components/gh-members-import-mapping-input.hbs -add|ember-template-lint|no-action|9|36|9|36|05358b6ec6e9afbaa47416266c49f40a3ffb4490|1743984000000|1754352000000|1759536000000|app/components/gh-members-import-table.hbs -add|ember-template-lint|no-action|10|36|10|36|c5ce93cf577ec47970f715ed83ed11a63adb7a63|1743984000000|1754352000000|1759536000000|app/components/gh-members-import-table.hbs -add|ember-template-lint|no-action|36|43|36|43|66cebfc8448eced0bccf3faa57b4af0cd633e65e|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|37|47|37|47|70f3e9aa9a9aa52142c4e0c015a8f173d12b05ed|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|56|41|56|41|43cc094c1a6b50ecd24c8af325dfdfcac863bb14|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|57|41|57|41|e7f429eefd04a55d4ef1875fe601da1b69964364|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|87|50|87|50|0e827c1770073f988535ceb9d6c49808a153d896|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|104|39|104|39|5cbc9d2abf29e108bfc207579df1206485e2a74d|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|105|43|105|43|1f2dd4961e9757ede9706bb0aa9b8baf9c49b22b|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|116|132|116|132|90dbb84741c72aa86a601e1cb95c066bd53898bd|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|123|46|123|46|56ca074eb0236b8becc4084423056a8ffa4453e9|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|158|73|158|73|b07bf9d50af5f00861571521b150cf6504b90704|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|172|56|172|56|38755451c044c56040684339301c21b2aab49ecb|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|190|50|190|50|9f1c3c88187e5db774f97704269e372f8331eba5|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|196|50|196|50|97acfb2045b33a97621258596b631362ad4c56d5|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|202|51|202|51|358336432fcb413c522c5f1ff3062a68ef9f449f|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|208|50|208|50|78a45cbb7eafdda134d96f6035b0026f339e75ad|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|214|50|214|50|693211baf08c011e77284b483c30e28ecaf63520|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|223|105|223|105|de5b68b49193c72f85c0e478f151a00180321d91|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|236|167|236|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|601|163|601|163|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|607|34|607|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|616|47|616|47|67551960e57b2ad06d24289e0d6f256dc5635cae|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|617|51|617|51|50e3029f4c845049ff10130cf0dc2ea06c7a3d2d|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|632|47|632|47|0d852775b4028d61c2c91b5d821c79de3cdbd1de|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|633|51|633|51|194439ec4cb10e176eecb1f55c2995c00f6c67b4|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|647|47|647|47|3be93048908ab43d74726c3983982fcb9a3570e3|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|648|51|648|51|40871d259cc307345b8096e4215ae58e5886b724|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|674|166|674|166|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|681|34|681|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|686|44|686|44|d2abbb4bb55b6cb1131ca0bc56c31632b32b980c|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|687|44|687|44|3ede83bd64d206d665edb4f1b73f03b4122edfad|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|697|47|697|47|13b7064b520a924d9e57a4a680621ce979d23923|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|698|51|698|51|b0fc38b818f4ca2613684588e4122e12da0090b9|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|713|47|713|47|f34f084dc72c079be9ba3eb93c255bd8853612bd|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|714|51|714|51|c5c09d001fa96a623649cc88ef13b3c6c164f05b|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|742|167|742|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|748|34|748|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|753|44|753|44|32101c0834d9e8d2caa87dee9cb1a92fe633cfde|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|754|44|754|44|c8a82286cfe4220cb2d8a059b1daf7f6c8d54cf5|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|764|47|764|47|31800fb83f1797de5d91b7007c48432cf2fae803|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|765|51|765|51|5ce0788874489341385f031810e9f7f62724aaf8|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|778|47|778|47|1cbd7d922a9d202772a9dca214d97bed18777d6e|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|779|51|779|51|16fb2c7c87dc282c6ee49a032aaaf22628b88084|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|810|168|810|168|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|816|34|816|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|823|50|823|50|d03e7bbf2b6de94b08fae1c33bd5a2f16874e03a|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|825|48|825|48|bca167f0250b40d56ff1ed40ec21bc88f8e27ec3|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|836|50|836|50|93ae447fb1054de4dbe501fc60167a6ff3273687|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|838|48|838|48|ecb9ed2577be7ea0300563f22d8e9fde2fed12a6|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|36|36|36|36|fed655605208b290a18b9f7da51a6cf7b40c0e9a|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|104|32|104|32|187e85e14470b453a1e6df8c5f18549d11c441a0|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|616|40|616|40|f290a04fd56f613d80d61244d161631f630185a8|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|632|40|632|40|c1af88109f705acc93fab4ee7b4d89096136ffe1|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|647|40|647|40|852cbb2c63e19a28d700d3b18e6f887edef303fa|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|697|40|697|40|58185c92e8b6261ea1483a70296d9fa837d3f2f5|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|713|40|713|40|c4353acd715c396564c69389edd0a52246d3b966|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|764|40|764|40|29f26e46559dc40d9724a05b7516cb52f1481aaa|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|778|40|778|40|42e0617f832585eaa056c9c66dffe1a126318faf|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|823|40|823|40|d1dccfeee5b103fac3b14d5b4567bc65ee08fd5a|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-passed-in-event-handlers|836|40|836|40|055c4b70aa8daba6b97077eefa95ebed7f7f5315|1743984000000|1754352000000|1759536000000|app/components/gh-post-settings-menu.hbs -add|ember-template-lint|no-action|4|14|4|14|c8f6146f9286ec1b289e28983ab446386f390f01|1743984000000|1754352000000|1759536000000|app/components/gh-psm-authors-input.hbs -add|ember-template-lint|no-action|6|14|6|14|3924d7cfb394cbcfd6b1bf9cf13a5040ac8f94b5|1743984000000|1754352000000|1759536000000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|10|20|10|20|8b7921c0514cfd3fec8c3a474187048bc26faf7f|1743984000000|1754352000000|1759536000000|app/components/gh-psm-tags-input.hbs -add|ember-template-lint|no-action|9|24|9|24|2e612be5e2b8e0b792f951c3c75b2f71df880365|1743984000000|1754352000000|1759536000000|app/components/gh-psm-template-select.hbs -add|ember-template-lint|no-action|7|16|7|16|86819b20fcc42bc1d4607519c1d45532ee337884|1743984000000|1754352000000|1759536000000|app/components/gh-psm-visibility-input.hbs -add|ember-template-lint|no-autofocus-attribute|13|16|13|16|fa0ffb960072633b72117849e3927673be0059af|1743984000000|1754352000000|1759536000000|app/components/gh-search-input.hbs -add|ember-template-lint|require-iframe-title|1|0|1|0|956ab219134ac63aec3fd2d35582076c21631b75|1743984000000|1754352000000|1759536000000|app/components/gh-site-iframe.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1743984000000|1754352000000|1759536000000|app/components/gh-text-input.hbs -add|ember-template-lint|no-action|1|51|1|51|674a942db62e014b25156b02d014f6c63b2f1cb2|1743984000000|1754352000000|1759536000000|app/components/gh-theme-error-li.hbs -add|ember-template-lint|no-action|2|11|2|11|2b1317e72b94ec31bf2700acc3f041e6be974b72|1743984000000|1754352000000|1759536000000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|7|13|7|13|add4b57d48167f809045245535d45bedb00cb753|1743984000000|1754352000000|1759536000000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|8|22|8|22|ce1eba2b791c0f120baf10871fd3949c1b9f6a79|1743984000000|1754352000000|1759536000000|app/components/gh-uploader.hbs -add|ember-template-lint|no-action|9|22|9|22|0209f233628ec084b87894b4be9073c29f2a4f47|1743984000000|1754352000000|1759536000000|app/components/gh-uploader.hbs -add|ember-template-lint|no-passed-in-event-handlers|4|4|4|4|3dedc53191768d81765eac4a7a049a9aba7df442|1743984000000|1754352000000|1759536000000|app/components/gh-url-input.hbs -add|ember-template-lint|no-action|1|71|1|71|2e6351f546807d88cc8eb9dbe8baa149468b5cb9|1743984000000|1754352000000|1759536000000|app/components/gh-view-title.hbs -add|ember-template-lint|no-invalid-role|1|0|1|0|3e651d38e0110e1be20e5082075db1b879b59a36|1743984000000|1754352000000|1759536000000|app/components/gh-view-title.hbs -add|ember-template-lint|no-action|5|50|5|50|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-impersonate-member.hbs -add|ember-template-lint|no-action|5|74|5|74|d465b362b15b90cf42a093e72895155f49cdf6f2|1743984000000|1754352000000|1759536000000|app/components/modal-impersonate-member.hbs -add|ember-template-lint|no-action|43|57|43|57|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|50|56|50|56|190532b9954beb4e7e9e0f1c51d170e64d4a5315|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|56|34|56|34|ff609af61e9159dfc5386543d559f6d217d39531|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|57|29|57|29|9a0a72738b6e1a4f46415b2328c37d1814562717|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|110|89|110|89|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|116|91|116|91|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|119|116|119|116|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|129|120|129|120|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|132|103|132|103|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|143|112|143|112|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|147|110|147|110|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|153|97|153|97|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|156|112|156|112|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|160|99|160|99|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|163|110|163|110|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|171|91|171|91|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|174|102|174|102|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|181|95|181|95|031d04576149d3034549aa3d14bc26da704cd70c|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-action|185|102|185|102|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-import-members.hbs -add|ember-template-lint|no-invalid-interactive|28|24|28|24|42a29ae16e22270f0590c9ce5caa7bfec541ca0b|1743984000000|1754352000000|1759536000000|app/components/modal-member-tier.hbs -add|ember-template-lint|no-action|5|57|5|57|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|14|45|14|45|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|23|59|23|59|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|23|83|23|83|d465b362b15b90cf42a093e72895155f49cdf6f2|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|34|31|34|31|a8ad062b8379233b7970fe5ea74296fdf5011567|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|47|82|47|82|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|49|16|49|16|d465b362b15b90cf42a093e72895155f49cdf6f2|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|55|113|55|113|c259009ff744c2e9f7bb273e0eb3a3879036ba85|1743984000000|1754352000000|1759536000000|app/components/modal-members-label-form.hbs -add|ember-template-lint|no-action|4|53|4|53|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|no-action|50|89|50|89|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|no-action|54|71|54|71|141d456b03124abca146e58e4ae15825fdd040bb|1743984000000|1754352000000|1759536000000|app/components/modal-unsubscribe-members.hbs -add|ember-template-lint|require-valid-alt-text|4|12|4|12|8369d1b06deac93e8c8e05444670c15182aea434|1743984000000|1754352000000|1759536000000|app/templates/application-error.hbs -add|ember-template-lint|no-action|20|31|20|31|3aa834e53af871a821ebb1b47f7a04f925c2b593|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|21|35|21|35|ae65e93ed2b79a307e0eba50b154fe84ee1ae210|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|37|31|37|31|eefdee43411bdd45c2786b9e826e6b550fd6212d|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|38|35|38|35|a8e4bd4c57a8f2df65749b0cfa4349da22b2a0aa|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|55|31|55|31|1709109776bf3fc47aaecc21e6d3ec8a0489ad6b|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|56|35|56|35|8000241a81189d3876d264331ec0c9b6476df076|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|73|31|73|31|6756e119daad4aa143724e9b56a6aef744d65251|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|74|35|74|35|26b1d89c0e5bbcd629a215903c0819d35f798aa6|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|20|24|20|24|f0b7babba7593639d68dadae2f19e7144dd8c63e|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|37|24|37|24|2692530760cb1f7156dcf9570aacf0f8baca2770|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|55|24|55|24|ce0d7e2e732b22ce3643fb9b1ac6ecef07c275ff|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-passed-in-event-handlers|73|24|73|24|80681fcec2258c3d81a231bbd635aa1f03ff1452|1743984000000|1754352000000|1759536000000|app/templates/setup.hbs -add|ember-template-lint|no-action|6|108|6|108|ccc38f66549f9baedaa3b9943ae6634ea8f99e69|1743984000000|1754352000000|1759536000000|app/templates/tags.hbs -add|ember-template-lint|no-action|7|110|7|110|c3819ce2b6989e8596be570ed0c9fb82b5012521|1743984000000|1754352000000|1759536000000|app/templates/tags.hbs -add|ember-template-lint|require-valid-alt-text|15|32|15|32|80c1ce6724481312363dc4e1db42bf28b41909f2|1743984000000|1754352000000|1759536000000|app/templates/whatsnew.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|45|104|45|104|156670ca427c49c51f0a94f862b286ccc9466d92|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|65|131|65|131|156670ca427c49c51f0a94f862b286ccc9466d92|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|100|93|100|93|156670ca427c49c51f0a94f862b286ccc9466d92|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|50|89|50|89|0be75355d0dd43dafc60091285ba906c43350d19|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|73|57|73|57|0be75355d0dd43dafc60091285ba906c43350d19|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|78|57|78|57|0be75355d0dd43dafc60091285ba906c43350d19|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|require-context-role|89|131|89|131|0be75355d0dd43dafc60091285ba906c43350d19|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/footer.hbs -add|ember-template-lint|no-action|190|24|190|24|c8306856104d54d12e3db50acab26094d0793fb3|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|36|51|36|51|b8aae2daed1c14cf280800b3d282d11fb14851a4|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|49|28|49|28|571c3d774ed33480f528b54b323b23bfd7148eee|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-unknown-arguments-for-builtin-components|79|24|79|24|b8aae2daed1c14cf280800b3d282d11fb14851a4|1743984000000|1754352000000|1759536000000|app/components/gh-nav-menu/main.hbs -add|ember-template-lint|no-invalid-interactive|8|51|8|51|66a27dbed218d15e49e91c72a93215ad0d90f778|1743984000000|1754352000000|1759536000000|app/components/gh-power-select/trigger.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1743984000000|1754352000000|1759536000000|app/components/gh-token-input/label-token.hbs -add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1743984000000|1754352000000|1759536000000|app/components/gh-token-input/tag-token.hbs -add|ember-template-lint|no-action|8|19|8|19|73ac7d3892fcbcf15c3d5c44fca14dd21016daea|1743984000000|1754352000000|1759536000000|app/components/gh-token-input/trigger.hbs -add|ember-template-lint|no-positive-tabindex|46|8|46|8|6118264a9a0599fab6ad4da7264c1bfffa88687e|1743984000000|1754352000000|1759536000000|app/components/gh-token-input/trigger.hbs -add|ember-template-lint|require-iframe-title|27|20|27|20|94e58d11848d5613900c2188ba63dac41f4c03bb|1743984000000|1754352000000|1759536000000|app/components/modals/email-preview.hbs -add|ember-template-lint|require-iframe-title|42|16|42|16|a3292b469dc37f2f4791e7f224b0b65c8ecf5d18|1743984000000|1754352000000|1759536000000|app/components/modals/email-preview.hbs -add|ember-template-lint|no-autofocus-attribute|21|20|21|20|942419d05c04ded6716f09faecd6b1ab55418121|1743984000000|1754352000000|1759536000000|app/components/modals/new-custom-integration.hbs -add|ember-template-lint|no-invalid-interactive|2|37|2|37|e21ba31f54b631a428c28a1c9f88d0dc66f2f5fc|1743984000000|1754352000000|1759536000000|app/components/modals/search.hbs -add|ember-template-lint|no-redundant-role|6|20|6|20|bc4fbabe3d468440d8a2c70e92cec991caca41e2|1745798400000|1756166400000|1761350400000|app/components/gh-post-bookmark.hbs -add|ember-template-lint|no-redundant-role|14|64|14|64|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1745798400000|1756166400000|1761350400000|app/components/gh-post-bookmark.hbs -add|ember-template-lint|no-redundant-role|85|24|85|24|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1745798400000|1756166400000|1761350400000|app/components/modal-post-success.hbs -add|ember-template-lint|no-redundant-role|136|24|136|24|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1745798400000|1756166400000|1761350400000|app/components/modal-post-success.hbs -add|ember-template-lint|no-redundant-role|91|40|91|40|9d2eded16257516b455504637aab4057b3c0c9ef|1745798400000|1756166400000|1761350400000|app/templates/mentions.hbs -add|ember-template-lint|no-redundant-role|113|20|113|20|0418319e2dce98b674dbb6657d185f465d21f87d|1745798400000|1756166400000|1761350400000|app/templates/mentions.hbs -add|ember-template-lint|no-redundant-role|11|20|11|20|bc4fbabe3d468440d8a2c70e92cec991caca41e2|1745798400000|1756166400000|1761350400000|app/components/dashboard/onboarding/share-modal.hbs -remove|ember-template-lint|no-action|73|82|73|82|f30d469e4ae668f05aca2f92a124a6b4748847a3|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|80|92|80|92|f30d469e4ae668f05aca2f92a124a6b4748847a3|1730678400000|1741046400000|1746230400000|app/components/gh-post-settings-menu.hbs -remove|ember-template-lint|no-action|5|14|5|14|a90edd9a99596008f60bfcdbc6befe7fe8d26321|1730678400000|1741046400000|1746230400000|app/components/gh-psm-tags-input.hbs -remove|ember-template-lint|no-action|6|14|6|14|3924d7cfb394cbcfd6b1bf9cf13a5040ac8f94b5|1743984000000|1754352000000|1759536000000|app/components/gh-psm-tags-input.hbs -remove|ember-template-lint|no-action|10|20|10|20|8b7921c0514cfd3fec8c3a474187048bc26faf7f|1743984000000|1754352000000|1759536000000|app/components/gh-psm-tags-input.hbs +add|ember-template-lint|no-action|2|54|2|54|8618d17e29821f45d8809ad2d6cf6053b825f7fe|1746489600000|||app/components/gh-billing-update-button.hbs +add|ember-template-lint|no-action|5|11|5|11|8eaebb48eca1563c6e0b18581df84ab59188d971|1746489600000|||app/components/gh-cm-editor.hbs +add|ember-template-lint|no-passed-in-event-handlers|5|4|5|4|3a763e253744b070633bb8bd424b6c8e55f6b20a|1746489600000|||app/components/gh-cm-editor.hbs +add|ember-template-lint|no-invalid-interactive|1|103|1|103|534029ab0ba1b74eff4a2f31c8b4dd9f1460316a|1746489600000|||app/components/gh-context-menu.hbs +add|ember-template-lint|no-invalid-interactive|5|53|5|53|9647ef6afba919b2af04fe551b0fdf0fb63be849|1746489600000|||app/components/gh-context-menu.hbs +add|ember-template-lint|no-action|5|18|5|18|0c80a75b2a80d404755333991c266c81c97c9cda|1746489600000|||app/components/gh-date-time-picker.hbs +add|ember-template-lint|require-input-label|11|16|11|16|36ecd3af7ac0e4bbafbf933cc20ff9f3ff8f0947|1746489600000|||app/components/gh-date-time-picker.hbs +add|ember-template-lint|require-input-label|29|8|29|8|334a3ea0fb16fabf58967294e125af8437504bdb|1746489600000|||app/components/gh-date-time-picker.hbs +add|ember-template-lint|no-action|9|19|9|19|d12bcf1144bfb2fe70e7ab0f66836f1c6207a589|1746489600000|||app/components/gh-editor.hbs +add|ember-template-lint|no-action|10|20|10|20|16d94650de2ffbe8ee3f2ce3ba5ca97a6304b739|1746489600000|||app/components/gh-editor.hbs +add|ember-template-lint|no-action|11|17|11|17|30d64b1bf8990e2f84c52665690739fcc726e9f7|1746489600000|||app/components/gh-editor.hbs +add|ember-template-lint|no-action|2|45|2|45|55b33496610b2f4ef6b9fe62713f4b4ddee37f19|1746489600000|||app/components/gh-fullscreen-modal.hbs +add|ember-template-lint|no-action|10|29|10|29|ebbd89a393bcec7f537f2104ace2a6b1941a19a7|1746489600000|||app/components/gh-fullscreen-modal.hbs +add|ember-template-lint|no-action|11|32|11|32|ab89b6f10c519be1271386203e9439d261eecd67|1746489600000|||app/components/gh-fullscreen-modal.hbs +add|ember-template-lint|no-action|13|36|13|36|3776877637b49b65deef537c68ae490b2fb081a9|1746489600000|||app/components/gh-fullscreen-modal.hbs +add|ember-template-lint|no-invalid-interactive|2|45|2|45|918fdec8490009c6197091e319d6ec52ee95b983|1746489600000|||app/components/gh-fullscreen-modal.hbs +add|ember-template-lint|link-href-attributes|8|8|8|8|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1746489600000|||app/components/gh-image-uploader-with-preview.hbs +add|ember-template-lint|no-invalid-interactive|8|60|8|60|2078c6e43d1e5548ae745b7ac8cb736f7d2aaf68|1746489600000|||app/components/gh-image-uploader-with-preview.hbs +add|ember-template-lint|require-valid-alt-text|3|13|3|13|079fc89fa5c7c47f6b0b219820cdda3819c44e26|1746489600000|||app/components/gh-image-uploader-with-preview.hbs +add|ember-template-lint|no-action|12|58|12|58|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-action|17|75|17|75|bbc5d9a459cd07e56d8c79dde619775b89d7cc89|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-action|22|52|22|52|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-action|31|16|31|16|4c64ddeaf795ee831d0d7346667a305814ca9855|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-action|32|15|32|15|b1bd53a513ad82434d5a0a9a96441a45d416d7ad|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-invalid-interactive|22|52|22|52|74dea739bef284d6557987ff3da53fa1278030e2|1746489600000|||app/components/gh-image-uploader.hbs +add|ember-template-lint|no-action|10|16|10|16|8d8dd8c2cb5f9910c2de5ca6acc76ee4262a876e|1746489600000|||app/components/gh-members-import-mapping-input.hbs +add|ember-template-lint|no-action|9|36|9|36|05358b6ec6e9afbaa47416266c49f40a3ffb4490|1746489600000|||app/components/gh-members-import-table.hbs +add|ember-template-lint|no-action|10|36|10|36|c5ce93cf577ec47970f715ed83ed11a63adb7a63|1746489600000|||app/components/gh-members-import-table.hbs +add|ember-template-lint|no-redundant-role|6|20|6|20|bc4fbabe3d468440d8a2c70e92cec991caca41e2|1746489600000|||app/components/gh-post-bookmark.hbs +add|ember-template-lint|no-redundant-role|14|64|14|64|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1746489600000|||app/components/gh-post-bookmark.hbs +add|ember-template-lint|no-action|36|43|36|43|66cebfc8448eced0bccf3faa57b4af0cd633e65e|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|37|47|37|47|70f3e9aa9a9aa52142c4e0c015a8f173d12b05ed|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|56|41|56|41|43cc094c1a6b50ecd24c8af325dfdfcac863bb14|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|57|41|57|41|e7f429eefd04a55d4ef1875fe601da1b69964364|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|87|50|87|50|0e827c1770073f988535ceb9d6c49808a153d896|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|104|39|104|39|5cbc9d2abf29e108bfc207579df1206485e2a74d|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|105|43|105|43|1f2dd4961e9757ede9706bb0aa9b8baf9c49b22b|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|116|132|116|132|90dbb84741c72aa86a601e1cb95c066bd53898bd|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|123|46|123|46|56ca074eb0236b8becc4084423056a8ffa4453e9|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|158|73|158|73|b07bf9d50af5f00861571521b150cf6504b90704|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|172|56|172|56|38755451c044c56040684339301c21b2aab49ecb|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|190|50|190|50|9f1c3c88187e5db774f97704269e372f8331eba5|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|196|50|196|50|97acfb2045b33a97621258596b631362ad4c56d5|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|202|51|202|51|358336432fcb413c522c5f1ff3062a68ef9f449f|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|208|50|208|50|78a45cbb7eafdda134d96f6035b0026f339e75ad|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|214|50|214|50|693211baf08c011e77284b483c30e28ecaf63520|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|223|105|223|105|de5b68b49193c72f85c0e478f151a00180321d91|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|236|167|236|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|601|163|601|163|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|607|34|607|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|616|47|616|47|67551960e57b2ad06d24289e0d6f256dc5635cae|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|617|51|617|51|50e3029f4c845049ff10130cf0dc2ea06c7a3d2d|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|632|47|632|47|0d852775b4028d61c2c91b5d821c79de3cdbd1de|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|633|51|633|51|194439ec4cb10e176eecb1f55c2995c00f6c67b4|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|647|47|647|47|3be93048908ab43d74726c3983982fcb9a3570e3|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|648|51|648|51|40871d259cc307345b8096e4215ae58e5886b724|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|674|166|674|166|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|681|34|681|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|686|44|686|44|d2abbb4bb55b6cb1131ca0bc56c31632b32b980c|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|687|44|687|44|3ede83bd64d206d665edb4f1b73f03b4122edfad|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|697|47|697|47|13b7064b520a924d9e57a4a680621ce979d23923|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|698|51|698|51|b0fc38b818f4ca2613684588e4122e12da0090b9|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|713|47|713|47|f34f084dc72c079be9ba3eb93c255bd8853612bd|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|714|51|714|51|c5c09d001fa96a623649cc88ef13b3c6c164f05b|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|742|167|742|167|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|748|34|748|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|753|44|753|44|32101c0834d9e8d2caa87dee9cb1a92fe633cfde|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|754|44|754|44|c8a82286cfe4220cb2d8a059b1daf7f6c8d54cf5|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|764|47|764|47|31800fb83f1797de5d91b7007c48432cf2fae803|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|765|51|765|51|5ce0788874489341385f031810e9f7f62724aaf8|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|778|47|778|47|1cbd7d922a9d202772a9dca214d97bed18777d6e|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|779|51|779|51|16fb2c7c87dc282c6ee49a032aaaf22628b88084|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|810|168|810|168|0145b67f0faef0aad141c6a4269c35c6ef8f0a47|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|816|34|816|34|3d44a2ad21d60d18bed6f79265caa4887361aaa4|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|823|50|823|50|d03e7bbf2b6de94b08fae1c33bd5a2f16874e03a|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|825|48|825|48|bca167f0250b40d56ff1ed40ec21bc88f8e27ec3|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|836|50|836|50|93ae447fb1054de4dbe501fc60167a6ff3273687|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|838|48|838|48|ecb9ed2577be7ea0300563f22d8e9fde2fed12a6|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|36|36|36|36|fed655605208b290a18b9f7da51a6cf7b40c0e9a|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|104|32|104|32|187e85e14470b453a1e6df8c5f18549d11c441a0|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|616|40|616|40|f290a04fd56f613d80d61244d161631f630185a8|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|632|40|632|40|c1af88109f705acc93fab4ee7b4d89096136ffe1|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|647|40|647|40|852cbb2c63e19a28d700d3b18e6f887edef303fa|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|697|40|697|40|58185c92e8b6261ea1483a70296d9fa837d3f2f5|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|713|40|713|40|c4353acd715c396564c69389edd0a52246d3b966|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|764|40|764|40|29f26e46559dc40d9724a05b7516cb52f1481aaa|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|778|40|778|40|42e0617f832585eaa056c9c66dffe1a126318faf|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|823|40|823|40|d1dccfeee5b103fac3b14d5b4567bc65ee08fd5a|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-passed-in-event-handlers|836|40|836|40|055c4b70aa8daba6b97077eefa95ebed7f7f5315|1746489600000|||app/components/gh-post-settings-menu.hbs +add|ember-template-lint|no-action|4|14|4|14|c8f6146f9286ec1b289e28983ab446386f390f01|1746489600000|||app/components/gh-psm-authors-input.hbs +add|ember-template-lint|no-action|9|24|9|24|2e612be5e2b8e0b792f951c3c75b2f71df880365|1746489600000|||app/components/gh-psm-template-select.hbs +add|ember-template-lint|no-action|7|16|7|16|86819b20fcc42bc1d4607519c1d45532ee337884|1746489600000|||app/components/gh-psm-visibility-input.hbs +add|ember-template-lint|no-autofocus-attribute|13|16|13|16|fa0ffb960072633b72117849e3927673be0059af|1746489600000|||app/components/gh-search-input.hbs +add|ember-template-lint|require-iframe-title|1|0|1|0|956ab219134ac63aec3fd2d35582076c21631b75|1746489600000|||app/components/gh-site-iframe.hbs +add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1746489600000|||app/components/gh-text-input.hbs +add|ember-template-lint|no-action|1|51|1|51|674a942db62e014b25156b02d014f6c63b2f1cb2|1746489600000|||app/components/gh-theme-error-li.hbs +add|ember-template-lint|no-action|2|11|2|11|2b1317e72b94ec31bf2700acc3f041e6be974b72|1746489600000|||app/components/gh-uploader.hbs +add|ember-template-lint|no-action|7|13|7|13|add4b57d48167f809045245535d45bedb00cb753|1746489600000|||app/components/gh-uploader.hbs +add|ember-template-lint|no-action|8|22|8|22|ce1eba2b791c0f120baf10871fd3949c1b9f6a79|1746489600000|||app/components/gh-uploader.hbs +add|ember-template-lint|no-action|9|22|9|22|0209f233628ec084b87894b4be9073c29f2a4f47|1746489600000|||app/components/gh-uploader.hbs +add|ember-template-lint|no-passed-in-event-handlers|4|4|4|4|3dedc53191768d81765eac4a7a049a9aba7df442|1746489600000|||app/components/gh-url-input.hbs +add|ember-template-lint|no-action|1|71|1|71|2e6351f546807d88cc8eb9dbe8baa149468b5cb9|1746489600000|||app/components/gh-view-title.hbs +add|ember-template-lint|no-invalid-role|1|0|1|0|3e651d38e0110e1be20e5082075db1b879b59a36|1746489600000|||app/components/gh-view-title.hbs +add|ember-template-lint|no-action|5|50|5|50|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-impersonate-member.hbs +add|ember-template-lint|no-action|5|74|5|74|d465b362b15b90cf42a093e72895155f49cdf6f2|1746489600000|||app/components/modal-impersonate-member.hbs +add|ember-template-lint|no-action|43|57|43|57|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|50|56|50|56|190532b9954beb4e7e9e0f1c51d170e64d4a5315|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|56|34|56|34|ff609af61e9159dfc5386543d559f6d217d39531|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|57|29|57|29|9a0a72738b6e1a4f46415b2328c37d1814562717|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|110|89|110|89|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|116|91|116|91|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|119|116|119|116|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|129|120|129|120|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|132|103|132|103|7e581bf2ffd5254ae851201e1f23cb9eaa9b198b|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|143|112|143|112|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|147|110|147|110|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|153|97|153|97|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|156|112|156|112|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|160|99|160|99|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|163|110|163|110|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|171|91|171|91|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|174|102|174|102|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|181|95|181|95|031d04576149d3034549aa3d14bc26da704cd70c|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-action|185|102|185|102|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-import-members.hbs +add|ember-template-lint|no-invalid-interactive|28|24|28|24|42a29ae16e22270f0590c9ce5caa7bfec541ca0b|1746489600000|||app/components/modal-member-tier.hbs +add|ember-template-lint|no-action|5|57|5|57|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|14|45|14|45|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|23|59|23|59|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|23|83|23|83|d465b362b15b90cf42a093e72895155f49cdf6f2|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|34|31|34|31|a8ad062b8379233b7970fe5ea74296fdf5011567|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|47|82|47|82|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|49|16|49|16|d465b362b15b90cf42a093e72895155f49cdf6f2|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-action|55|113|55|113|c259009ff744c2e9f7bb273e0eb3a3879036ba85|1746489600000|||app/components/modal-members-label-form.hbs +add|ember-template-lint|no-redundant-role|85|24|85|24|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1746489600000|||app/components/modal-post-success.hbs +add|ember-template-lint|no-redundant-role|136|24|136|24|ce988c0098c6e4845fc3307eb523b8b1687a3ecf|1746489600000|||app/components/modal-post-success.hbs +add|ember-template-lint|no-action|4|53|4|53|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-unsubscribe-members.hbs +add|ember-template-lint|no-action|50|89|50|89|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-unsubscribe-members.hbs +add|ember-template-lint|no-action|54|71|54|71|141d456b03124abca146e58e4ae15825fdd040bb|1746489600000|||app/components/modal-unsubscribe-members.hbs +add|ember-template-lint|require-valid-alt-text|4|12|4|12|8369d1b06deac93e8c8e05444670c15182aea434|1746489600000|||app/templates/application-error.hbs +add|ember-template-lint|no-redundant-role|91|40|91|40|9d2eded16257516b455504637aab4057b3c0c9ef|1746489600000|||app/templates/mentions.hbs +add|ember-template-lint|no-redundant-role|113|20|113|20|0418319e2dce98b674dbb6657d185f465d21f87d|1746489600000|||app/templates/mentions.hbs +add|ember-template-lint|no-action|20|31|20|31|3aa834e53af871a821ebb1b47f7a04f925c2b593|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|21|35|21|35|ae65e93ed2b79a307e0eba50b154fe84ee1ae210|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|37|31|37|31|eefdee43411bdd45c2786b9e826e6b550fd6212d|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|38|35|38|35|a8e4bd4c57a8f2df65749b0cfa4349da22b2a0aa|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|55|31|55|31|1709109776bf3fc47aaecc21e6d3ec8a0489ad6b|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|56|35|56|35|8000241a81189d3876d264331ec0c9b6476df076|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|73|31|73|31|6756e119daad4aa143724e9b56a6aef744d65251|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|74|35|74|35|26b1d89c0e5bbcd629a215903c0819d35f798aa6|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-passed-in-event-handlers|20|24|20|24|f0b7babba7593639d68dadae2f19e7144dd8c63e|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-passed-in-event-handlers|37|24|37|24|2692530760cb1f7156dcf9570aacf0f8baca2770|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-passed-in-event-handlers|55|24|55|24|ce0d7e2e732b22ce3643fb9b1ac6ecef07c275ff|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-passed-in-event-handlers|73|24|73|24|80681fcec2258c3d81a231bbd635aa1f03ff1452|1746489600000|||app/templates/setup.hbs +add|ember-template-lint|no-action|6|108|6|108|ccc38f66549f9baedaa3b9943ae6634ea8f99e69|1746489600000|||app/templates/tags.hbs +add|ember-template-lint|no-action|7|110|7|110|c3819ce2b6989e8596be570ed0c9fb82b5012521|1746489600000|||app/templates/tags.hbs +add|ember-template-lint|require-valid-alt-text|15|32|15|32|80c1ce6724481312363dc4e1db42bf28b41909f2|1746489600000|||app/templates/whatsnew.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|45|104|45|104|156670ca427c49c51f0a94f862b286ccc9466d92|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|65|131|65|131|156670ca427c49c51f0a94f862b286ccc9466d92|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|100|93|100|93|156670ca427c49c51f0a94f862b286ccc9466d92|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|require-context-role|50|89|50|89|0be75355d0dd43dafc60091285ba906c43350d19|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|require-context-role|73|57|73|57|0be75355d0dd43dafc60091285ba906c43350d19|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|require-context-role|78|57|78|57|0be75355d0dd43dafc60091285ba906c43350d19|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|require-context-role|89|131|89|131|0be75355d0dd43dafc60091285ba906c43350d19|1746489600000|||app/components/gh-nav-menu/footer.hbs +add|ember-template-lint|no-action|19|16|19|16|3696846a8a04d429559abebaaf5dab2c6387c21f|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-action|47|26|47|26|3b76c38861ddcdfaa277e272a1d27293c2659524|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-action|175|24|175|24|c8306856104d54d12e3db50acab26094d0793fb3|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-invalid-interactive|47|26|47|26|da9f7c0f319619ff98a53fd679c47841cfaa3c1d|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-redundant-fn|5|70|5|70|d8c5269c9b4ca3aec0fc5b8e3d6a997e115dbc92|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|36|51|36|51|b8aae2daed1c14cf280800b3d282d11fb14851a4|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|49|28|49|28|571c3d774ed33480f528b54b323b23bfd7148eee|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-unknown-arguments-for-builtin-components|79|24|79|24|b8aae2daed1c14cf280800b3d282d11fb14851a4|1746489600000|||app/components/gh-nav-menu/main.hbs +add|ember-template-lint|no-invalid-interactive|8|51|8|51|66a27dbed218d15e49e91c72a93215ad0d90f778|1746489600000|||app/components/gh-power-select/trigger.hbs +add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1746489600000|||app/components/gh-token-input/label-token.hbs +add|ember-template-lint|no-yield-only|1|0|1|0|a5fa6e8c1e0f03fb31b5cd17770e4368d44932e4|1746489600000|||app/components/gh-token-input/tag-token.hbs +add|ember-template-lint|no-action|8|19|8|19|73ac7d3892fcbcf15c3d5c44fca14dd21016daea|1746489600000|||app/components/gh-token-input/trigger.hbs +add|ember-template-lint|no-positive-tabindex|46|8|46|8|6118264a9a0599fab6ad4da7264c1bfffa88687e|1746489600000|||app/components/gh-token-input/trigger.hbs +add|ember-template-lint|require-iframe-title|27|20|27|20|94e58d11848d5613900c2188ba63dac41f4c03bb|1746489600000|||app/components/modals/email-preview.hbs +add|ember-template-lint|require-iframe-title|42|16|42|16|a3292b469dc37f2f4791e7f224b0b65c8ecf5d18|1746489600000|||app/components/modals/email-preview.hbs +add|ember-template-lint|no-autofocus-attribute|21|20|21|20|942419d05c04ded6716f09faecd6b1ab55418121|1746489600000|||app/components/modals/new-custom-integration.hbs +add|ember-template-lint|no-invalid-interactive|2|37|2|37|e21ba31f54b631a428c28a1c9f88d0dc66f2f5fc|1746489600000|||app/components/modals/search.hbs +add|ember-template-lint|no-redundant-role|11|20|11|20|bc4fbabe3d468440d8a2c70e92cec991caca41e2|1746489600000|||app/components/dashboard/onboarding/share-modal.hbs diff --git a/ghost/admin/.lint-todorc.js b/ghost/admin/.lint-todorc.js index c4e2a8e98ab..3c2848387f2 100644 --- a/ghost/admin/.lint-todorc.js +++ b/ghost/admin/.lint-todorc.js @@ -1,8 +1,5 @@ module.exports = { 'ember-template-lint': { - daysToDecay: { - warn: 120, - error: 180, - } + daysToDecay: null } - }; +}; diff --git a/ghost/admin/app/styles/layouts/content.css b/ghost/admin/app/styles/layouts/content.css index e4551987f84..f326ac52f53 100644 --- a/ghost/admin/app/styles/layouts/content.css +++ b/ghost/admin/app/styles/layouts/content.css @@ -2270,11 +2270,11 @@ span.dropdown .gh-post-list-cta > span { } .feature-trafficAnalytics .gh-post-analytics-sidebar-item:hover { color: var(--black); - background: var(--whitegrey); + background: var(--whitegrey-l1); } .feature-trafficAnalytics .gh-post-analytics-sidebar-item.active { - background: var(--whitegrey); + background: var(--whitegrey-l1); color: var(--black); font-weight: 600; } @@ -2294,6 +2294,14 @@ span.dropdown .gh-post-list-cta > span { border-bottom: 1px solid var(--whitegrey); } +.feature-trafficAnalytics .gh-tabs-analytics.no-tabs .tab-panel-selected { + margin: 0 24px; +} + +.feature-trafficAnalytics .gh-tabs-analytics.no-tabs { + padding: 20px 0; +} + .feature-trafficAnalytics .gh-tabs-analytics .tab-list .tab { border: none; padding: 0 0 12px; @@ -2396,6 +2404,10 @@ span.dropdown .gh-post-list-cta > span { background: none; } +.feature-trafficAnalytics .gh-tabs-analytics.no-tabs .tab-selected:before { + display: none; +} + @media (max-width: 1320px) { .feature-trafficAnalytics .gh-post-analytics-content { grid-template-columns: auto 240px; diff --git a/ghost/core/core/server/api/endpoints/stats.js b/ghost/core/core/server/api/endpoints/stats.js index d9effc47748..dda0c19aa05 100644 --- a/ghost/core/core/server/api/endpoints/stats.js +++ b/ghost/core/core/server/api/endpoints/stats.js @@ -206,6 +206,38 @@ const controller = { async query(frame) { return await statsService.api.getReferrersForPost(frame.data.id, frame.options); } + }, + postGrowthStats: { + headers: { + cacheInvalidate: false + }, + data: [ + 'id' + ], + validation: { + data: { + id: { + type: 'string', + required: true + } + } + }, + permissions: { + docName: 'posts', + method: 'browse' + }, + cache: statsService.cache, + generateCacheKeyData(frame) { + return { + method: 'postGrowthStats', + data: { + id: frame.data.id + } + }; + }, + async query(frame) { + return await statsService.api.getGrowthStatsForPost(frame.data.id); + } } }; diff --git a/ghost/core/core/server/services/email-service/EmailServiceWrapper.js b/ghost/core/core/server/services/email-service/EmailServiceWrapper.js index 401ff9d62a6..91be63f5e2d 100644 --- a/ghost/core/core/server/services/email-service/EmailServiceWrapper.js +++ b/ghost/core/core/server/services/email-service/EmailServiceWrapper.js @@ -34,7 +34,7 @@ class EmailServiceWrapper { const lexicalLib = require('../../lib/lexical'); const urlUtils = require('../../../shared/url-utils'); const memberAttribution = require('../member-attribution'); - const linkReplacer = require('@tryghost/link-replacer'); + const linkReplacer = require('../lib/link-replacer'); const linkTracking = require('../link-tracking'); const audienceFeedback = require('../audience-feedback'); const storageUtils = require('../../adapters/storage/utils'); diff --git a/ghost/link-replacer/lib/link-replacer.js b/ghost/core/core/server/services/lib/link-replacer.js similarity index 97% rename from ghost/link-replacer/lib/link-replacer.js rename to ghost/core/core/server/services/lib/link-replacer.js index 1d5cdb4869d..44ea918d73e 100644 --- a/ghost/link-replacer/lib/link-replacer.js +++ b/ghost/core/core/server/services/lib/link-replacer.js @@ -2,7 +2,7 @@ class LinkReplacer { /** * Replaces the links in the provided HTML * @param {string} html - * @param {(url: URL, originalPath: string): Promise} replaceLink + * @param {(url: URL, originalPath: string) => Promise} replaceLink * @param {object} options * @param {string} [options.base] If you want to replace relative links, this will replace them to an absolute link and call the replaceLink method too * @returns {Promise} diff --git a/ghost/member-attribution/lib/AttributionBuilder.js b/ghost/core/core/server/services/member-attribution/AttributionBuilder.js similarity index 100% rename from ghost/member-attribution/lib/AttributionBuilder.js rename to ghost/core/core/server/services/member-attribution/AttributionBuilder.js diff --git a/ghost/member-attribution/lib/MemberAttributionService.js b/ghost/core/core/server/services/member-attribution/MemberAttributionService.js similarity index 100% rename from ghost/member-attribution/lib/MemberAttributionService.js rename to ghost/core/core/server/services/member-attribution/MemberAttributionService.js diff --git a/ghost/member-attribution/lib/OutboundLinkTagger.js b/ghost/core/core/server/services/member-attribution/OutboundLinkTagger.js similarity index 98% rename from ghost/member-attribution/lib/OutboundLinkTagger.js rename to ghost/core/core/server/services/member-attribution/OutboundLinkTagger.js index 671e84c0ef2..34d5ea0b222 100644 --- a/ghost/member-attribution/lib/OutboundLinkTagger.js +++ b/ghost/core/core/server/services/member-attribution/OutboundLinkTagger.js @@ -1,5 +1,5 @@ const {slugify} = require('@tryghost/string'); -const LinkReplacer = require('@tryghost/link-replacer'); +const LinkReplacer = require('../lib/link-replacer'); const blockedReferrerDomains = [ // Facebook has some restrictions on the 'ref' attribute (max 15 chars + restricted character set) that breaks links if we add ?ref=longer-string diff --git a/ghost/member-attribution/lib/ReferrerTranslator.js b/ghost/core/core/server/services/member-attribution/ReferrerTranslator.js similarity index 100% rename from ghost/member-attribution/lib/ReferrerTranslator.js rename to ghost/core/core/server/services/member-attribution/ReferrerTranslator.js diff --git a/ghost/member-attribution/lib/UrlHistory.js b/ghost/core/core/server/services/member-attribution/UrlHistory.js similarity index 100% rename from ghost/member-attribution/lib/UrlHistory.js rename to ghost/core/core/server/services/member-attribution/UrlHistory.js diff --git a/ghost/member-attribution/lib/UrlTranslator.js b/ghost/core/core/server/services/member-attribution/UrlTranslator.js similarity index 100% rename from ghost/member-attribution/lib/UrlTranslator.js rename to ghost/core/core/server/services/member-attribution/UrlTranslator.js diff --git a/ghost/core/core/server/services/member-attribution/index.js b/ghost/core/core/server/services/member-attribution/index.js index 597fd919b10..dcc7fa88cc3 100644 --- a/ghost/core/core/server/services/member-attribution/index.js +++ b/ghost/core/core/server/services/member-attribution/index.js @@ -11,9 +11,11 @@ class MemberAttributionServiceWrapper { } // Wire up all the dependencies - const { - MemberAttributionService, UrlTranslator, ReferrerTranslator, AttributionBuilder, OutboundLinkTagger - } = require('@tryghost/member-attribution'); + const MemberAttributionService = require('./MemberAttributionService'); + const UrlTranslator = require('./UrlTranslator'); + const ReferrerTranslator = require('./ReferrerTranslator'); + const AttributionBuilder = require('./AttributionBuilder'); + const OutboundLinkTagger = require('./OutboundLinkTagger'); const models = require('../../models'); const urlTranslator = new UrlTranslator({ diff --git a/ghost/core/core/server/services/members/importer/MembersCSVImporter.js b/ghost/core/core/server/services/members/importer/MembersCSVImporter.js index f4dc988ce24..8ca12aae9bc 100644 --- a/ghost/core/core/server/services/members/importer/MembersCSVImporter.js +++ b/ghost/core/core/server/services/members/importer/MembersCSVImporter.js @@ -33,8 +33,8 @@ const DEFAULT_CSV_HEADER_MAPPING = { * @property {string} storagePath - The path to store CSV's in before importing * @property {Function} getTimezone - function returning currently configured timezone * @property {() => Object} getMembersRepository - member model access instance for data access and manipulation - * @property {() => Promise} getDefaultTier - async function returning default Member Tier - * @property {(string) => Promise} getTierByName - async function returning Member Tier by name + * @property {() => Promise} getDefaultTier - async function returning default Member Tier + * @property {(string) => Promise} getTierByName - async function returning Member Tier by name * @property {Function} sendEmail - function sending an email * @property {(string) => boolean} isSet - Method checking if specific feature is enabled * @property {({job, offloaded, name}) => void} addJob - Method registering an async job diff --git a/ghost/core/core/server/services/members/members-api/services/PaymentsService.js b/ghost/core/core/server/services/members/members-api/services/PaymentsService.js index 7f19fbfa5cf..83c209725e9 100644 --- a/ghost/core/core/server/services/members/members-api/services/PaymentsService.js +++ b/ghost/core/core/server/services/members/members-api/services/PaymentsService.js @@ -1,15 +1,17 @@ const logging = require('@tryghost/logging'); const DomainEvents = require('@tryghost/domain-events'); -const {TierCreatedEvent, TierPriceChangeEvent, TierNameChangeEvent} = require('@tryghost/tiers'); -const OfferCreatedEvent = require('@tryghost/members-offers').events.OfferCreatedEvent; +const TierCreatedEvent = require('../../../../../../core/server/services/tiers/TierCreatedEvent'); +const TierPriceChangeEvent = require('../../../../../../core/server/services/tiers/TierPriceChangeEvent'); +const TierNameChangeEvent = require('../../../../../../core/server/services/tiers/TierNameChangeEvent'); +const OfferCreatedEvent = require('../../../../../../core/server/services/offers/domain/events/OfferCreatedEvent'); const {BadRequestError} = require('@tryghost/errors'); class PaymentsService { /** * @param {object} deps * @param {import('bookshelf').Model} deps.Offer - * @param {import('@tryghost/members-offers/lib/application/OffersAPI')} deps.offersAPI - * @param {import('@tryghost/members-stripe-service/lib/StripeAPI')} deps.stripeAPIService + * @param {import('../../../offers/application/OffersAPI')} deps.offersAPI + * @param {import('../../../stripe/StripeAPI')} deps.stripeAPIService * @param {{get(key: string): any}} deps.settingsCache */ constructor(deps) { @@ -55,7 +57,7 @@ class PaymentsService { /** * @param {object} params - * @param {Tier} params.tier + * @param {import('../../../tiers/Tier')} params.tier * @param {Tier.Cadence} params.cadence * @param {Offer} [params.offer] * @param {Member} [params.member] @@ -127,7 +129,7 @@ class PaymentsService { if (member && isAuthenticated) { customer = await this.getCustomerForMember(member); } - + const data = { priceId: (await this.getPriceForDonations()).id, metadata, @@ -135,7 +137,7 @@ class PaymentsService { cancelUrl: cancelUrl, customer, customerEmail: !customer && email ? email : null, - personalNote: personalNote + personalNote: personalNote }; @@ -181,7 +183,7 @@ class PaymentsService { } /** - * @param {import('@tryghost/tiers').Tier} tier + * @param {import('../../../tiers/Tier')} tier * @returns {Promise<{id: string}>} */ async getProductForTier(tier) { @@ -209,7 +211,7 @@ class PaymentsService { } /** - * @param {import('@tryghost/tiers').Tier} tier + * @param {import('../../../tiers/Tier')} tier * @returns {Promise} */ async createProductForTier(tier) { @@ -222,7 +224,7 @@ class PaymentsService { } /** - * @param {import('@tryghost/tiers').Tier} tier + * @param {import('../../../tiers/Tier')} tier * @returns {Promise} */ async updateNameForTierProducts(tier) { @@ -396,7 +398,7 @@ class PaymentsService { } /** - * @param {import('@tryghost/tiers').Tier} tier + * @param {import('../../../tiers/Tier')} tier * @param {'month'|'year'} cadence * @returns {Promise<{id: string}>} */ @@ -440,7 +442,7 @@ class PaymentsService { } /** - * @param {import('@tryghost/tiers').Tier} tier + * @param {import('../../../tiers/Tier')} tier * @param {'month'|'year'} cadence * @returns {Promise} */ diff --git a/ghost/core/core/server/services/offers/OfferBookshelfRepository.js b/ghost/core/core/server/services/offers/OfferBookshelfRepository.js index 5d43a010395..50927ba8d8d 100644 --- a/ghost/core/core/server/services/offers/OfferBookshelfRepository.js +++ b/ghost/core/core/server/services/offers/OfferBookshelfRepository.js @@ -1,7 +1,7 @@ const {flowRight} = require('lodash'); const {mapKeyValues, mapQuery} = require('@tryghost/mongo-utils'); const DomainEvents = require('@tryghost/domain-events'); -const {Offer} = require('@tryghost/members-offers'); +const Offer = require('./domain/models/Offer'); const sentry = require('../../../shared/sentry'); const logger = require('@tryghost/logging'); @@ -93,7 +93,7 @@ class OfferBookshelfRepository { * @private * @param {import('bookshelf').Model} model * @param {BaseOptions} options - * @returns {Promise} + * @returns {Promise} */ async mapToOffer(model, options) { const json = model.toJSON(); @@ -140,7 +140,7 @@ class OfferBookshelfRepository { /** * @param {string} id * @param {BaseOptions} [options] - * @returns {Promise} + * @returns {Promise} */ async getById(id, options) { const model = await this.OfferModel.findOne({id}, { @@ -158,7 +158,7 @@ class OfferBookshelfRepository { /** * @param {string} id stripe_coupon_id * @param {BaseOptions} [options] - * @returns {Promise} + * @returns {Promise} */ async getByStripeCouponId(id, options) { const model = await this.OfferModel.findOne({stripe_coupon_id: id}, { @@ -175,7 +175,7 @@ class OfferBookshelfRepository { /** * @param {ListOptions} options - * @returns {Promise} + * @returns {Promise} */ async getAll(options) { const models = await this.OfferModel.findAll({ @@ -194,7 +194,7 @@ class OfferBookshelfRepository { } /** - * @param {import('@tryghost/members-offers').Offer} offer + * @param {import('./domain/models/Offer')} offer * @param {BaseOptions} [options] * @returns {Promise} */ diff --git a/ghost/offers/lib/OffersModule.js b/ghost/core/core/server/services/offers/OffersModule.js similarity index 100% rename from ghost/offers/lib/OffersModule.js rename to ghost/core/core/server/services/offers/OffersModule.js diff --git a/ghost/offers/lib/application/OfferMapper.js b/ghost/core/core/server/services/offers/application/OfferMapper.js similarity index 100% rename from ghost/offers/lib/application/OfferMapper.js rename to ghost/core/core/server/services/offers/application/OfferMapper.js diff --git a/ghost/offers/lib/application/OffersAPI.js b/ghost/core/core/server/services/offers/application/OffersAPI.js similarity index 100% rename from ghost/offers/lib/application/OffersAPI.js rename to ghost/core/core/server/services/offers/application/OffersAPI.js diff --git a/ghost/offers/lib/application/UniqueChecker.js b/ghost/core/core/server/services/offers/application/UniqueChecker.js similarity index 100% rename from ghost/offers/lib/application/UniqueChecker.js rename to ghost/core/core/server/services/offers/application/UniqueChecker.js diff --git a/ghost/offers/lib/domain/errors/index.js b/ghost/core/core/server/services/offers/domain/errors/index.js similarity index 100% rename from ghost/offers/lib/domain/errors/index.js rename to ghost/core/core/server/services/offers/domain/errors/index.js diff --git a/ghost/offers/lib/domain/events/OfferCodeChangeEvent.js b/ghost/core/core/server/services/offers/domain/events/OfferCodeChangeEvent.js similarity index 100% rename from ghost/offers/lib/domain/events/OfferCodeChangeEvent.js rename to ghost/core/core/server/services/offers/domain/events/OfferCodeChangeEvent.js diff --git a/ghost/offers/lib/domain/events/OfferCreatedEvent.js b/ghost/core/core/server/services/offers/domain/events/OfferCreatedEvent.js similarity index 100% rename from ghost/offers/lib/domain/events/OfferCreatedEvent.js rename to ghost/core/core/server/services/offers/domain/events/OfferCreatedEvent.js diff --git a/ghost/offers/lib/domain/models/Offer.js b/ghost/core/core/server/services/offers/domain/models/Offer.js similarity index 100% rename from ghost/offers/lib/domain/models/Offer.js rename to ghost/core/core/server/services/offers/domain/models/Offer.js diff --git a/ghost/offers/lib/domain/models/OfferAmount.js b/ghost/core/core/server/services/offers/domain/models/OfferAmount.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferAmount.js rename to ghost/core/core/server/services/offers/domain/models/OfferAmount.js diff --git a/ghost/offers/lib/domain/models/OfferCadence.js b/ghost/core/core/server/services/offers/domain/models/OfferCadence.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferCadence.js rename to ghost/core/core/server/services/offers/domain/models/OfferCadence.js diff --git a/ghost/offers/lib/domain/models/OfferCode.js b/ghost/core/core/server/services/offers/domain/models/OfferCode.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferCode.js rename to ghost/core/core/server/services/offers/domain/models/OfferCode.js diff --git a/ghost/offers/lib/domain/models/OfferCreatedAt.js b/ghost/core/core/server/services/offers/domain/models/OfferCreatedAt.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferCreatedAt.js rename to ghost/core/core/server/services/offers/domain/models/OfferCreatedAt.js diff --git a/ghost/offers/lib/domain/models/OfferCurrency.js b/ghost/core/core/server/services/offers/domain/models/OfferCurrency.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferCurrency.js rename to ghost/core/core/server/services/offers/domain/models/OfferCurrency.js diff --git a/ghost/offers/lib/domain/models/OfferDescription.js b/ghost/core/core/server/services/offers/domain/models/OfferDescription.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferDescription.js rename to ghost/core/core/server/services/offers/domain/models/OfferDescription.js diff --git a/ghost/offers/lib/domain/models/OfferDuration.js b/ghost/core/core/server/services/offers/domain/models/OfferDuration.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferDuration.js rename to ghost/core/core/server/services/offers/domain/models/OfferDuration.js diff --git a/ghost/offers/lib/domain/models/OfferName.js b/ghost/core/core/server/services/offers/domain/models/OfferName.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferName.js rename to ghost/core/core/server/services/offers/domain/models/OfferName.js diff --git a/ghost/offers/lib/domain/models/OfferStatus.js b/ghost/core/core/server/services/offers/domain/models/OfferStatus.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferStatus.js rename to ghost/core/core/server/services/offers/domain/models/OfferStatus.js diff --git a/ghost/offers/lib/domain/models/OfferTitle.js b/ghost/core/core/server/services/offers/domain/models/OfferTitle.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferTitle.js rename to ghost/core/core/server/services/offers/domain/models/OfferTitle.js diff --git a/ghost/offers/lib/domain/models/OfferType.js b/ghost/core/core/server/services/offers/domain/models/OfferType.js similarity index 100% rename from ghost/offers/lib/domain/models/OfferType.js rename to ghost/core/core/server/services/offers/domain/models/OfferType.js diff --git a/ghost/offers/lib/domain/models/shared/ValueObject.js b/ghost/core/core/server/services/offers/domain/models/shared/ValueObject.js similarity index 100% rename from ghost/offers/lib/domain/models/shared/ValueObject.js rename to ghost/core/core/server/services/offers/domain/models/shared/ValueObject.js diff --git a/ghost/core/core/server/services/offers/service.js b/ghost/core/core/server/services/offers/service.js index d5cd66ab34e..d8adf66f232 100644 --- a/ghost/core/core/server/services/offers/service.js +++ b/ghost/core/core/server/services/offers/service.js @@ -1,10 +1,9 @@ -const OffersModule = require('@tryghost/members-offers'); - const DynamicRedirectManager = require('../lib/DynamicRedirectManager'); const config = require('../../../shared/config'); const urlUtils = require('../../../shared/url-utils'); const models = require('../../models'); const OfferBookshelfRepository = require('./OfferBookshelfRepository'); +const OffersModule = require('./OffersModule'); let redirectManager; diff --git a/ghost/core/core/server/services/stats/PostsStatsService.js b/ghost/core/core/server/services/stats/PostsStatsService.js index 020c47e3672..d2bd1e10f88 100644 --- a/ghost/core/core/server/services/stats/PostsStatsService.js +++ b/ghost/core/core/server/services/stats/PostsStatsService.js @@ -159,6 +159,48 @@ class PostsStatsService { } } + async getGrowthStatsForPost(postId) { + try { + const freeMembers = await this.knex('members_created_events as mce') + .countDistinct('mce.member_id as free_members') + .leftJoin('members_subscription_created_events as msce', function () { + this.on('mce.member_id', '=', 'msce.member_id') + .andOn('mce.attribution_id', '=', 'msce.attribution_id'); + }) + .where('mce.attribution_id', postId) + .where('mce.attribution_type', 'post') + .where('msce.id', null); + + const paidMembers = await this.knex('members_subscription_created_events as msce') + .countDistinct('msce.member_id as paid_members') + .where('msce.attribution_id', postId) + .where('msce.attribution_type', 'post'); + + const mrr = await this.knex('members_subscription_created_events as msce') + .sum('mpse.mrr_delta as mrr') + .join('members_paid_subscription_events as mpse', function () { + this.on('mpse.subscription_id', '=', 'msce.subscription_id'); + this.andOn('mpse.member_id', '=', 'msce.member_id'); + }) + .where('msce.attribution_id', postId) + .where('msce.attribution_type', 'post'); + + return { + data: [ + { + post_id: postId, + free_members: freeMembers[0].free_members || 0, + paid_members: paidMembers[0].paid_members || 0, + mrr: mrr[0].mrr || 0 + } + ] + }; + } catch (error) { + logging.error(`Error fetching growth stats for post ${postId}:`, error); + return {data: []}; + } + } + /** * Build a subquery/CTE for free_members count (Post-level) * (Signed up on Post, Paid Elsewhere/Never) diff --git a/ghost/core/core/server/services/stats/StatsService.js b/ghost/core/core/server/services/stats/StatsService.js index 1c269d99be9..ada6e13430a 100644 --- a/ghost/core/core/server/services/stats/StatsService.js +++ b/ghost/core/core/server/services/stats/StatsService.js @@ -89,6 +89,13 @@ class StatsService { return result; } + /** + * @param {string} postId + */ + async getGrowthStatsForPost(postId) { + return await this.posts.getGrowthStatsForPost(postId); + } + /** * @param {object} deps * diff --git a/ghost/tiers/lib/InMemoryTierRepository.js b/ghost/core/core/server/services/tiers/InMemoryTierRepository.js similarity index 100% rename from ghost/tiers/lib/InMemoryTierRepository.js rename to ghost/core/core/server/services/tiers/InMemoryTierRepository.js diff --git a/ghost/tiers/lib/Tier.js b/ghost/core/core/server/services/tiers/Tier.js similarity index 100% rename from ghost/tiers/lib/Tier.js rename to ghost/core/core/server/services/tiers/Tier.js diff --git a/ghost/tiers/lib/TierActivatedEvent.js b/ghost/core/core/server/services/tiers/TierActivatedEvent.js similarity index 94% rename from ghost/tiers/lib/TierActivatedEvent.js rename to ghost/core/core/server/services/tiers/TierActivatedEvent.js index 18b717118bf..76d49d81217 100644 --- a/ghost/tiers/lib/TierActivatedEvent.js +++ b/ghost/core/core/server/services/tiers/TierActivatedEvent.js @@ -1,6 +1,6 @@ /** * @typedef {object} TierActivatedEventData - * @prop {Tier} tier + * @prop {import('./Tier')} tier */ class TierActivatedEvent { diff --git a/ghost/tiers/lib/TierArchivedEvent.js b/ghost/core/core/server/services/tiers/TierArchivedEvent.js similarity index 94% rename from ghost/tiers/lib/TierArchivedEvent.js rename to ghost/core/core/server/services/tiers/TierArchivedEvent.js index e2a74cba4ec..35bf69bc4e6 100644 --- a/ghost/tiers/lib/TierArchivedEvent.js +++ b/ghost/core/core/server/services/tiers/TierArchivedEvent.js @@ -1,6 +1,6 @@ /** * @typedef {object} TierArchivedEventData - * @prop {Tier} tier + * @prop {import('./Tier')} tier */ class TierArchivedEvent { diff --git a/ghost/tiers/lib/TierCreatedEvent.js b/ghost/core/core/server/services/tiers/TierCreatedEvent.js similarity index 94% rename from ghost/tiers/lib/TierCreatedEvent.js rename to ghost/core/core/server/services/tiers/TierCreatedEvent.js index 112226295ca..851319cb95c 100644 --- a/ghost/tiers/lib/TierCreatedEvent.js +++ b/ghost/core/core/server/services/tiers/TierCreatedEvent.js @@ -1,6 +1,6 @@ /** * @typedef {object} TierCreatedEventData - * @prop {Tier} tier + * @prop {import('./Tier')} tier */ class TierCreatedEvent { diff --git a/ghost/tiers/lib/TierNameChangeEvent.js b/ghost/core/core/server/services/tiers/TierNameChangeEvent.js similarity index 94% rename from ghost/tiers/lib/TierNameChangeEvent.js rename to ghost/core/core/server/services/tiers/TierNameChangeEvent.js index a03bb282357..21dc191fa1b 100644 --- a/ghost/tiers/lib/TierNameChangeEvent.js +++ b/ghost/core/core/server/services/tiers/TierNameChangeEvent.js @@ -1,6 +1,6 @@ /** * @typedef {object} TierNameChangeEventData - * @prop {Tier} tier + * @prop {import('./Tier')} tier */ class TierNameChangeEvent { diff --git a/ghost/tiers/lib/TierPriceChangeEvent.js b/ghost/core/core/server/services/tiers/TierPriceChangeEvent.js similarity index 94% rename from ghost/tiers/lib/TierPriceChangeEvent.js rename to ghost/core/core/server/services/tiers/TierPriceChangeEvent.js index b373ead7a57..c7d3ff4eb43 100644 --- a/ghost/tiers/lib/TierPriceChangeEvent.js +++ b/ghost/core/core/server/services/tiers/TierPriceChangeEvent.js @@ -1,6 +1,6 @@ /** * @typedef {object} TierPriceChangeEventData - * @prop {Tier} tier + * @prop {import('./Tier')} tier */ class TierPriceChangeEvent { diff --git a/ghost/core/core/server/services/tiers/TierRepository.js b/ghost/core/core/server/services/tiers/TierRepository.js index 12012a854b5..9260b875119 100644 --- a/ghost/core/core/server/services/tiers/TierRepository.js +++ b/ghost/core/core/server/services/tiers/TierRepository.js @@ -1,15 +1,15 @@ -const {Tier} = require('@tryghost/tiers'); +const Tier = require('./Tier'); const nql = require('@tryghost/nql'); /** - * @typedef {import('@tryghost/tiers/lib/TiersAPI').ITierRepository} ITierRepository + * @typedef {import('./TiersAPI').ITierRepository} ITierRepository */ /** * @implements {ITierRepository} */ module.exports = class TierRepository { - /** @type {import('@tryghost/tiers/lib/Tier')[]} */ + /** @type {import('./Tier')[]} */ #store = []; /** @type {Object.} */ #ids = {}; @@ -44,7 +44,7 @@ module.exports = class TierRepository { } /** - * @param {import('@tryghost/tiers/lib/Tier')} tier + * @param {import('./Tier')} tier * @returns {any} */ toPrimitive(tier) { @@ -83,7 +83,7 @@ module.exports = class TierRepository { /** * @param {object} [options] * @param {string} [options.filter] - * @returns {Promise} + * @returns {Promise} */ async getAll(options = {}) { const filter = nql(); @@ -97,7 +97,7 @@ module.exports = class TierRepository { /** * @param {import('bson-objectid').default} id - * @returns {Promise} + * @returns {Promise} */ async getById(id) { const found = this.#store.find((item) => { @@ -112,7 +112,7 @@ module.exports = class TierRepository { } /** - * @param {import('@tryghost/tiers/lib/Tier')} tier + * @param {import('./Tier')} tier * @returns {Promise} */ async save(tier) { diff --git a/ghost/tiers/lib/TiersAPI.js b/ghost/core/core/server/services/tiers/TiersAPI.js similarity index 100% rename from ghost/tiers/lib/TiersAPI.js rename to ghost/core/core/server/services/tiers/TiersAPI.js diff --git a/ghost/core/core/server/services/tiers/service.js b/ghost/core/core/server/services/tiers/service.js index e7deb4d7bdd..e31d34ba472 100644 --- a/ghost/core/core/server/services/tiers/service.js +++ b/ghost/core/core/server/services/tiers/service.js @@ -5,7 +5,7 @@ class TiersServiceWrapper { return; } - const {TiersAPI} = require('@tryghost/tiers'); + const TiersAPI = require('./TiersAPI'); const DomainEvents = require('@tryghost/domain-events'); const models = require('../../models'); diff --git a/ghost/core/core/server/web/api/endpoints/admin/routes.js b/ghost/core/core/server/web/api/endpoints/admin/routes.js index 02810c61d71..aa37294e498 100644 --- a/ghost/core/core/server/web/api/endpoints/admin/routes.js +++ b/ghost/core/core/server/web/api/endpoints/admin/routes.js @@ -159,6 +159,7 @@ module.exports = function apiRoutes() { router.get('/stats/top-posts', mw.authAdminApi, http(api.stats.topPosts)); router.get('/stats/top-content', mw.authAdminApi, http(api.stats.topContent)); router.get('/stats/posts/:id/top-referrers', mw.authAdminApi, http(api.stats.postReferrersAlpha)); + router.get('/stats/posts/:id/growth', mw.authAdminApi, http(api.stats.postGrowthStats)); } // ## Labels diff --git a/ghost/core/package.json b/ghost/core/package.json index b089f84facd..e1e9024beb0 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -98,11 +98,8 @@ "@tryghost/kg-lexical-html-renderer": "1.3.5", "@tryghost/kg-mobiledoc-html-renderer": "7.1.1", "@tryghost/limit-service": "1.2.15", - "@tryghost/link-replacer": "0.0.0", "@tryghost/logging": "2.4.21", - "@tryghost/member-attribution": "0.0.0", "@tryghost/members-csv": "0.0.0", - "@tryghost/members-offers": "0.0.0", "@tryghost/metrics": "1.0.37", "@tryghost/mw-error-handler": "0.0.0", "@tryghost/mw-vhost": "0.0.0", @@ -113,12 +110,12 @@ "@tryghost/pretty-cli": "1.2.46", "@tryghost/prometheus-metrics": "0.0.0", "@tryghost/promise": "0.3.14", + "@tryghost/referrer-parser": "0.1.1", "@tryghost/request": "1.0.10", "@tryghost/root-utils": "0.3.32", "@tryghost/security": "0.0.0", "@tryghost/social-urls": "0.1.47", "@tryghost/string": "0.2.13", - "@tryghost/tiers": "0.0.0", "@tryghost/tpl": "0.1.34", "@tryghost/url-utils": "4.4.9", "@tryghost/validator": "0.2.16", @@ -148,6 +145,7 @@ "date-fns": "2.30.0", "dompurify": "3.2.5", "downsize": "0.0.8", + "entities": "4.5.0", "express": "4.21.2", "express-brute": "1.0.1", "express-hbs": "2.5.0", @@ -165,6 +163,7 @@ "gscan": "4.48.0", "handlebars": "4.7.8", "html-to-text": "5.1.1", + "html5parser": "2.0.2", "human-number": "2.0.4", "iconv-lite": "0.6.3", "image-size": "1.2.1", diff --git a/ghost/core/test/e2e-api/admin/stats.test.js b/ghost/core/test/e2e-api/admin/stats.test.js index 980d4de9b57..ba495f7133b 100644 --- a/ghost/core/test/e2e-api/admin/stats.test.js +++ b/ghost/core/test/e2e-api/admin/stats.test.js @@ -262,4 +262,16 @@ describe('Stats API', function () { }); }); }); + + describe('Post Growth Stats', function () { + it('Can fetch post growth stats', async function () { + await agent + .get(`/stats/posts/${fixtureManager.get('posts', 1).id}/growth`) + .expectStatus(200) + .expect(({body}) => { + assert.ok(body.stats, 'Response should contain a stats property'); + assert.ok(Array.isArray(body.stats), 'body.stats should be an array'); + }); + }); + }); }); diff --git a/ghost/link-replacer/test/LinkReplacer.test.js b/ghost/core/test/unit/server/services/lib/LinkReplacer.test.js similarity index 96% rename from ghost/link-replacer/test/LinkReplacer.test.js rename to ghost/core/test/unit/server/services/lib/LinkReplacer.test.js index 2528009da47..83f8cb34c88 100644 --- a/ghost/link-replacer/test/LinkReplacer.test.js +++ b/ghost/core/test/unit/server/services/lib/LinkReplacer.test.js @@ -1,5 +1,5 @@ const assert = require('assert/strict'); -const linkReplacer = require('../lib/link-replacer'); +const linkReplacer = require('../../../../../core/server/services/lib/link-replacer'); const html5parser = require('html5parser'); const sinon = require('sinon'); @@ -8,10 +8,6 @@ describe('LinkReplacementService', function () { sinon.restore(); }); - it('exported', function () { - assert.equal(require('../index'), linkReplacer); - }); - describe('replace', function () { it('Can replace to URL', async function () { const html = 'link'; diff --git a/ghost/link-replacer/test/fixtures/example-post.html b/ghost/core/test/unit/server/services/lib/fixtures/example-post.html similarity index 100% rename from ghost/link-replacer/test/fixtures/example-post.html rename to ghost/core/test/unit/server/services/lib/fixtures/example-post.html diff --git a/ghost/member-attribution/test/attribution.test.js b/ghost/core/test/unit/server/services/member-attribution/attribution.test.js similarity index 97% rename from ghost/member-attribution/test/attribution.test.js rename to ghost/core/test/unit/server/services/member-attribution/attribution.test.js index e0af6d4c556..a6c537bf15b 100644 --- a/ghost/member-attribution/test/attribution.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/attribution.test.js @@ -1,7 +1,7 @@ -require('should'); +const should = require('should'); -const UrlHistory = require('../lib/UrlHistory'); -const AttributionBuilder = require('../lib/AttributionBuilder'); +const UrlHistory = require('../../../../../core/server/services/member-attribution/UrlHistory'); +const AttributionBuilder = require('../../../../../core/server/services/member-attribution/AttributionBuilder'); describe('AttributionBuilder', function () { let attributionBuilder; diff --git a/ghost/member-attribution/test/history.test.js b/ghost/core/test/unit/server/services/member-attribution/history.test.js similarity index 95% rename from ghost/member-attribution/test/history.test.js rename to ghost/core/test/unit/server/services/member-attribution/history.test.js index 4ddb864559f..d9493ec7a65 100644 --- a/ghost/member-attribution/test/history.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/history.test.js @@ -1,6 +1,6 @@ -require('should'); +const should = require('should'); -const UrlHistory = require('../lib/UrlHistory'); +const UrlHistory = require('../../../../../core/server/services/member-attribution/UrlHistory'); describe('UrlHistory', function () { it('sets history to empty array if invalid', function () { diff --git a/ghost/member-attribution/test/outbound-link-tagger.test.js b/ghost/core/test/unit/server/services/member-attribution/outbound-link-tagger.test.js similarity index 98% rename from ghost/member-attribution/test/outbound-link-tagger.test.js rename to ghost/core/test/unit/server/services/member-attribution/outbound-link-tagger.test.js index fcb3143b75d..a870c6a6be6 100644 --- a/ghost/member-attribution/test/outbound-link-tagger.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/outbound-link-tagger.test.js @@ -1,5 +1,7 @@ -const {OutboundLinkTagger} = require('../'); const assert = require('assert/strict'); +const should = require('should'); + +const OutboundLinkTagger = require('../../../../../core/server/services/member-attribution/OutboundLinkTagger'); describe('OutboundLinkTagger', function () { describe('Constructor', function () { diff --git a/ghost/member-attribution/test/referrer-translator.test.js b/ghost/core/test/unit/server/services/member-attribution/referrer-translator.test.js similarity index 98% rename from ghost/member-attribution/test/referrer-translator.test.js rename to ghost/core/test/unit/server/services/member-attribution/referrer-translator.test.js index bb98713185e..c7450725c3a 100644 --- a/ghost/member-attribution/test/referrer-translator.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/referrer-translator.test.js @@ -1,6 +1,6 @@ -require('should'); +const should = require('should'); -const ReferrerTranslator = require('../lib/ReferrerTranslator'); +const ReferrerTranslator = require('../../../../../core/server/services/member-attribution/ReferrerTranslator'); describe('ReferrerTranslator', function () { describe('Constructor', function () { diff --git a/ghost/member-attribution/test/service.test.js b/ghost/core/test/unit/server/services/member-attribution/service.test.js similarity index 98% rename from ghost/member-attribution/test/service.test.js rename to ghost/core/test/unit/server/services/member-attribution/service.test.js index 5a66ea52294..251c5f78e3c 100644 --- a/ghost/member-attribution/test/service.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/service.test.js @@ -1,6 +1,6 @@ -require('should'); +const should = require('should'); -const MemberAttributionService = require('../lib/MemberAttributionService'); +const MemberAttributionService = require('../../../../../core/server/services/member-attribution/MemberAttributionService'); describe('MemberAttributionService', function () { describe('Constructor', function () { diff --git a/ghost/member-attribution/test/url-translator.test.js b/ghost/core/test/unit/server/services/member-attribution/url-translator.test.js similarity index 98% rename from ghost/member-attribution/test/url-translator.test.js rename to ghost/core/test/unit/server/services/member-attribution/url-translator.test.js index 3794ebca24e..02d1f6327d7 100644 --- a/ghost/member-attribution/test/url-translator.test.js +++ b/ghost/core/test/unit/server/services/member-attribution/url-translator.test.js @@ -1,6 +1,6 @@ -require('should'); +const should = require('should'); -const UrlTranslator = require('../lib/UrlTranslator'); +const UrlTranslator = require('../../../../../core/server/services/member-attribution/UrlTranslator'); const models = { Post: { diff --git a/ghost/core/test/unit/server/services/members/importer/MembersCSVImporter.test.js b/ghost/core/test/unit/server/services/members/importer/MembersCSVImporter.test.js index cd8826c4e30..ce6378879bc 100644 --- a/ghost/core/test/unit/server/services/members/importer/MembersCSVImporter.test.js +++ b/ghost/core/test/unit/server/services/members/importer/MembersCSVImporter.test.js @@ -1,6 +1,6 @@ require('should'); -const Tier = require('@tryghost/tiers/lib/Tier'); +const Tier = require('../../../../../../core/server/services/tiers/Tier'); const ObjectID = require('bson-objectid').default; const assert = require('assert/strict'); const fs = require('fs-extra'); diff --git a/ghost/core/test/unit/server/services/members/members-api/services/payments.test.js b/ghost/core/test/unit/server/services/members/members-api/services/payments.test.js index d9125a12df4..fd3eb67ce69 100644 --- a/ghost/core/test/unit/server/services/members/members-api/services/payments.test.js +++ b/ghost/core/test/unit/server/services/members/members-api/services/payments.test.js @@ -1,7 +1,8 @@ const assert = require('assert/strict'); const sinon = require('sinon'); -const knex = require('knex'); -const {Tier} = require('@tryghost/tiers'); +const knex = require('knex').default; + +const Tier = require('../../../../../../../core/server/services/tiers/Tier'); const PaymentsService = require('../../../../../../../core/server/services/members/members-api/services/PaymentsService'); diff --git a/ghost/offers/test/lib/application/UniqueChecker.test.js b/ghost/core/test/unit/server/services/offers/application/UniqueChecker.test.js similarity index 94% rename from ghost/offers/test/lib/application/UniqueChecker.test.js rename to ghost/core/test/unit/server/services/offers/application/UniqueChecker.test.js index 7399e8f6b56..a4c57855c3f 100644 --- a/ghost/offers/test/lib/application/UniqueChecker.test.js +++ b/ghost/core/test/unit/server/services/offers/application/UniqueChecker.test.js @@ -1,6 +1,6 @@ const sinon = require('sinon'); const should = require('should'); -const UniqueChecker = require('../../../lib/application/UniqueChecker'); +const UniqueChecker = require('../../../../../../core/server/services/offers/application/UniqueChecker'); describe('UniqueChecker', function () { describe('#isUniqueCode', function () { diff --git a/ghost/offers/test/lib/domain/models/Offer.test.js b/ghost/core/test/unit/server/services/offers/domain/models/Offer.test.js similarity index 97% rename from ghost/offers/test/lib/domain/models/Offer.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/Offer.test.js index 89655dcb058..23bf01fa83a 100644 --- a/ghost/offers/test/lib/domain/models/Offer.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/Offer.test.js @@ -1,9 +1,9 @@ const should = require('should'); const ObjectID = require('bson-objectid').default; -const errors = require('../../../../lib/domain/errors'); -const Offer = require('../../../../lib/domain/models/Offer'); -const OfferName = require('../../../../lib/domain/models/OfferName'); -const OfferCode = require('../../../../lib/domain/models/OfferCode'); +const errors = require('../../../../../../../core/server/services/offers/domain/errors'); +const Offer = require('../../../../../../../core/server/services/offers/domain/models/Offer'); +const OfferName = require('../../../../../../../core/server/services/offers/domain/models/OfferName'); +const OfferCode = require('../../../../../../../core/server/services/offers/domain/models/OfferCode'); function createUniqueChecker(dupe) { return { diff --git a/ghost/offers/test/lib/domain/models/OfferAmount.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferAmount.test.js similarity index 98% rename from ghost/offers/test/lib/domain/models/OfferAmount.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferAmount.test.js index bc89700a3fd..bfdcb1695c9 100644 --- a/ghost/offers/test/lib/domain/models/OfferAmount.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferAmount.test.js @@ -1,4 +1,6 @@ -const {OfferPercentageAmount, OfferFixedAmount, OfferTrialAmount} = require('../../../../lib/domain/models/OfferAmount'); +const should = require('should'); + +const {OfferPercentageAmount, OfferFixedAmount, OfferTrialAmount} = require('../../../../../../../core/server/services/offers/domain/models/OfferAmount'); describe('OfferAmount', function () { describe('OfferPercentageAmount', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferCadence.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferCadence.test.js similarity index 90% rename from ghost/offers/test/lib/domain/models/OfferCadence.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferCadence.test.js index 48f12d32973..9e0be39003d 100644 --- a/ghost/offers/test/lib/domain/models/OfferCadence.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferCadence.test.js @@ -1,4 +1,6 @@ -const OfferCadence = require('../../../../lib/domain/models/OfferCadence'); +const should = require('should'); + +const OfferCadence = require('../../../../../../../core/server/services/offers/domain/models/OfferCadence'); describe('OfferCadence', function () { describe('OfferCadence.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferCode.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferCode.test.js similarity index 92% rename from ghost/offers/test/lib/domain/models/OfferCode.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferCode.test.js index 8ac1d8ed0ae..1b9f67d8d9d 100644 --- a/ghost/offers/test/lib/domain/models/OfferCode.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferCode.test.js @@ -1,4 +1,6 @@ -const OfferCode = require('../../../../lib/domain/models/OfferCode'); +const should = require('should'); + +const OfferCode = require('../../../../../../../core/server/services/offers/domain/models/OfferCode'); describe('OfferCode', function () { describe('OfferCode.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferCurrency.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferCurrency.test.js similarity index 94% rename from ghost/offers/test/lib/domain/models/OfferCurrency.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferCurrency.test.js index 58f67b4290c..033f80f638e 100644 --- a/ghost/offers/test/lib/domain/models/OfferCurrency.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferCurrency.test.js @@ -1,4 +1,6 @@ -const OfferCurrency = require('../../../../lib/domain/models/OfferCurrency'); +const should = require('should'); + +const OfferCurrency = require('../../../../../../../core/server/services/offers/domain/models/OfferCurrency'); describe('OfferCurrency', function () { describe('OfferCurrency.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferDescription.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferDescription.test.js similarity index 93% rename from ghost/offers/test/lib/domain/models/OfferDescription.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferDescription.test.js index dcf31fe83fb..263781c8289 100644 --- a/ghost/offers/test/lib/domain/models/OfferDescription.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferDescription.test.js @@ -1,4 +1,6 @@ -const OfferDescription = require('../../../../lib/domain/models/OfferDescription'); +const should = require('should'); + +const OfferDescription = require('../../../../../../../core/server/services/offers/domain/models/OfferDescription'); describe('OfferDescription', function () { describe('OfferDescription.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferDuration.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferDuration.test.js similarity index 94% rename from ghost/offers/test/lib/domain/models/OfferDuration.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferDuration.test.js index f8aba18aef2..5106e8cc1f6 100644 --- a/ghost/offers/test/lib/domain/models/OfferDuration.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferDuration.test.js @@ -1,4 +1,6 @@ -const OfferDuration = require('../../../../lib/domain/models/OfferDuration'); +const should = require('should'); + +const OfferDuration = require('../../../../../../../core/server/services/offers/domain/models/OfferDuration'); describe('OfferDuration', function () { describe('OfferDuration.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferName.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferName.test.js similarity index 94% rename from ghost/offers/test/lib/domain/models/OfferName.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferName.test.js index 6d1a39d69fa..967fa6c6fc9 100644 --- a/ghost/offers/test/lib/domain/models/OfferName.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferName.test.js @@ -1,4 +1,6 @@ -const OfferName = require('../../../../lib/domain/models/OfferName'); +const should = require('should'); + +const OfferName = require('../../../../../../../core/server/services/offers/domain/models/OfferName'); describe('OfferName', function () { describe('OfferName.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferStatus.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferStatus.test.js similarity index 86% rename from ghost/offers/test/lib/domain/models/OfferStatus.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferStatus.test.js index 77f74158029..d1c63a581f9 100644 --- a/ghost/offers/test/lib/domain/models/OfferStatus.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferStatus.test.js @@ -1,4 +1,6 @@ -const OfferStatus = require('../../../../lib/domain/models/OfferStatus'); +const should = require('should'); + +const OfferStatus = require('../../../../../../../core/server/services/offers/domain/models/OfferStatus'); describe('OfferStatus', function () { describe('OfferStatus.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferTitle.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferTitle.test.js similarity index 93% rename from ghost/offers/test/lib/domain/models/OfferTitle.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferTitle.test.js index 02ce1d8c10d..973f892c8da 100644 --- a/ghost/offers/test/lib/domain/models/OfferTitle.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferTitle.test.js @@ -1,4 +1,6 @@ -const OfferTitle = require('../../../../lib/domain/models/OfferTitle'); +const should = require('should'); + +const OfferTitle = require('../../../../../../../core/server/services/offers/domain/models/OfferTitle'); describe('OfferTitle', function () { describe('OfferTitle.create factory', function () { diff --git a/ghost/offers/test/lib/domain/models/OfferType.test.js b/ghost/core/test/unit/server/services/offers/domain/models/OfferType.test.js similarity index 92% rename from ghost/offers/test/lib/domain/models/OfferType.test.js rename to ghost/core/test/unit/server/services/offers/domain/models/OfferType.test.js index 7e92f29c80f..31beb1848b4 100644 --- a/ghost/offers/test/lib/domain/models/OfferType.test.js +++ b/ghost/core/test/unit/server/services/offers/domain/models/OfferType.test.js @@ -1,4 +1,6 @@ -const OfferType = require('../../../../lib/domain/models/OfferType'); +const should = require('should'); + +const OfferType = require('../../../../../../../core/server/services/offers/domain/models/OfferType'); describe('OfferType', function () { describe('OfferType.create factory', function () { diff --git a/ghost/core/test/unit/server/services/stats/posts.test.js b/ghost/core/test/unit/server/services/stats/posts.test.js index 5ed28676a69..84c84d0a08b 100644 --- a/ghost/core/test/unit/server/services/stats/posts.test.js +++ b/ghost/core/test/unit/server/services/stats/posts.test.js @@ -484,4 +484,20 @@ describe('PostsStatsService', function () { assert.equal(result.data[1].source, 'referrer_2'); }); }); + + describe('getGrowthStatsForPost', function () { + it('returns growth stats for a post', async function () { + await _createFreeSignup('post1', 'referrer_1'); + await _createPaidSignup('post1', 500, 'referrer_1'); + await _createPaidConversion('post1', 'post2', 500, 'referrer_1'); + + const result = await service.getGrowthStatsForPost('post1'); + + const expectedResults = [ + {post_id: 'post1', free_members: 2, paid_members: 1, mrr: 500} + ]; + + assert.deepEqual(result.data, expectedResults, 'Results should match expected order and counts for free_members desc'); + }); + }); }); diff --git a/ghost/tiers/test/Tier.test.js b/ghost/core/test/unit/server/services/tiers/Tier.test.js similarity index 93% rename from ghost/tiers/test/Tier.test.js rename to ghost/core/test/unit/server/services/tiers/Tier.test.js index 5a7a47ded2f..77cf950feea 100644 --- a/ghost/tiers/test/Tier.test.js +++ b/ghost/core/test/unit/server/services/tiers/Tier.test.js @@ -1,10 +1,10 @@ const assert = require('assert/strict'); -const ObjectID = require('bson-objectid'); -const Tier = require('../lib/Tier'); -const TierActivatedEvent = require('../lib/TierActivatedEvent'); -const TierArchivedEvent = require('../lib/TierArchivedEvent'); -const TierNameChangeEvent = require('../lib/TierNameChangeEvent'); -const TierPriceChangeEvent = require('../lib/TierPriceChangeEvent'); +const ObjectID = require('bson-objectid').default; +const Tier = require('../../../../../core/server/services/tiers/Tier'); +const TierActivatedEvent = require('../../../../../core/server/services/tiers/TierActivatedEvent'); +const TierArchivedEvent = require('../../../../../core/server/services/tiers/TierArchivedEvent'); +const TierNameChangeEvent = require('../../../../../core/server/services/tiers/TierNameChangeEvent'); +const TierPriceChangeEvent = require('../../../../../core/server/services/tiers/TierPriceChangeEvent'); async function assertError(fn, checkError) { let error; diff --git a/ghost/core/test/unit/server/services/tiers/TierRepository.test.js b/ghost/core/test/unit/server/services/tiers/TierRepository.test.js index 1aad4068a04..f7f1b94f51f 100644 --- a/ghost/core/test/unit/server/services/tiers/TierRepository.test.js +++ b/ghost/core/test/unit/server/services/tiers/TierRepository.test.js @@ -2,7 +2,7 @@ const assert = require('assert/strict'); const sinon = require('sinon'); const {Product: ProductModel} = require('../../../../../core/server/models/product'); const TierRepository = require('../../../../../core/server/services/tiers/TierRepository'); -const {Tier} = require('@tryghost/tiers'); +const Tier = require('../../../../../core/server/services/tiers/Tier'); describe('TierRepository', function () { after(function () { diff --git a/ghost/tiers/test/TiersAPI.test.js b/ghost/core/test/unit/server/services/tiers/TiersAPI.test.js similarity index 92% rename from ghost/tiers/test/TiersAPI.test.js rename to ghost/core/test/unit/server/services/tiers/TiersAPI.test.js index 4dab87d5db0..732312cd790 100644 --- a/ghost/tiers/test/TiersAPI.test.js +++ b/ghost/core/test/unit/server/services/tiers/TiersAPI.test.js @@ -1,6 +1,7 @@ const assert = require('assert/strict'); -const TiersAPI = require('../lib/TiersAPI'); -const InMemoryTierRepository = require('../lib/InMemoryTierRepository'); + +const TiersAPI = require('../../../../../core/server/services/tiers/TiersAPI'); +const InMemoryTierRepository = require('../../../../../core/server/services/tiers/InMemoryTierRepository'); describe('TiersAPI', function () { /** @type {TiersAPI.ITierRepository} */ diff --git a/ghost/email-service/test/email-renderer.test.js b/ghost/email-service/test/email-renderer.test.js index 738b023a8c7..341deeca906 100644 --- a/ghost/email-service/test/email-renderer.test.js +++ b/ghost/email-service/test/email-renderer.test.js @@ -2,7 +2,7 @@ const {EmailRenderer} = require('../'); const assert = require('assert/strict'); const cheerio = require('cheerio'); const {createModel, createModelClass} = require('./utils'); -const linkReplacer = require('@tryghost/link-replacer'); +const linkReplacer = require('../../core/core/server/services/lib/link-replacer'); const sinon = require('sinon'); const logging = require('@tryghost/logging'); const {HtmlValidate} = require('html-validate'); @@ -2701,7 +2701,7 @@ describe('Email renderer', function () { beforeEach(function () { renderedPost = '

Lexical Test

'; labsEnabled = true; // TODO: odd default because it means we're testing the unused email-customization template - + postUrl = 'http://example.com'; customSettings = { locale: 'fr', diff --git a/ghost/link-replacer/.eslintrc.js b/ghost/link-replacer/.eslintrc.js deleted file mode 100644 index c9c1bcb5226..00000000000 --- a/ghost/link-replacer/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/node' - ] -}; diff --git a/ghost/link-replacer/README.md b/ghost/link-replacer/README.md deleted file mode 100644 index 53507d11392..00000000000 --- a/ghost/link-replacer/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Link Replacement - -Replace links in a HTML string to add attribution and link tracking - - -## Usage - - -## Develop - -This is a monorepo package. - -Follow the instructions for the top-level repo. -1. `git clone` this repo & `cd` into it as usual -2. Run `yarn` to install top-level dependencies. - - - -## Test - -- `yarn lint` run just eslint -- `yarn test` run lint and tests - diff --git a/ghost/link-replacer/index.js b/ghost/link-replacer/index.js deleted file mode 100644 index fea9668ac4a..00000000000 --- a/ghost/link-replacer/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/link-replacer'); diff --git a/ghost/link-replacer/package.json b/ghost/link-replacer/package.json deleted file mode 100644 index 96356f2a22f..00000000000 --- a/ghost/link-replacer/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@tryghost/link-replacer", - "version": "0.0.0", - "repository": "https://github.com/TryGhost/Ghost/tree/main/packages/link-replacer", - "author": "Ghost Foundation", - "private": true, - "main": "index.js", - "scripts": { - "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --100 --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", - "test": "yarn test:unit", - "lint:code": "eslint *.js lib/ --ext .js --cache", - "lint": "yarn lint:code && yarn lint:test", - "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache" - }, - "files": [ - "index.js", - "lib" - ], - "devDependencies": { - "@probe.gl/bench": "4.1.0", - "c8": "8.0.1", - "mocha": "10.8.2", - "should": "13.2.3", - "sinon": "15.2.0" - }, - "dependencies": { - "entities": "4.5.0", - "html5parser": "2.0.2" - } -} diff --git a/ghost/link-replacer/test/.eslintrc.js b/ghost/link-replacer/test/.eslintrc.js deleted file mode 100644 index 829b601eb0a..00000000000 --- a/ghost/link-replacer/test/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/test' - ] -}; diff --git a/ghost/link-replacer/test/benchmark.js b/ghost/link-replacer/test/benchmark.js deleted file mode 100644 index bc9ffb15322..00000000000 --- a/ghost/link-replacer/test/benchmark.js +++ /dev/null @@ -1,14 +0,0 @@ -const {readFileSync} = require('node:fs'); -const {Bench} = require('@probe.gl/bench'); -const linkReplacer = require('../lib/link-replacer'); -const linkReplacerNew = require('../lib/link-replacer-new'); - -// load html from file in ./fixtures/example-post.html -const html = readFileSync('./test/fixtures/example-post.html', {encoding: 'utf8', flag: 'r'}); - -const bench = new Bench() - .group('LinkReplacer') - .addAsync('cheerio', () => linkReplacer.replace(html, () => new URL('https://google.com/test-dir?test-query'))) - .addAsync('html5parser', () => linkReplacerNew.replace(html, () => new URL('https://google.com/test-dir?test-query'))); - -bench.run(); diff --git a/ghost/member-attribution/.eslintrc.js b/ghost/member-attribution/.eslintrc.js deleted file mode 100644 index c9c1bcb5226..00000000000 --- a/ghost/member-attribution/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/node' - ] -}; diff --git a/ghost/member-attribution/README.md b/ghost/member-attribution/README.md deleted file mode 100644 index e42b1f12cc5..00000000000 --- a/ghost/member-attribution/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Member Attribution - - -## Usage - - -## Develop - -This is a monorepo package. - -Follow the instructions for the top-level repo. -1. `git clone` this repo & `cd` into it as usual -2. Run `yarn` to install top-level dependencies. - - - -## Test - -- `yarn lint` run just eslint -- `yarn test` run lint and tests - diff --git a/ghost/member-attribution/index.js b/ghost/member-attribution/index.js deleted file mode 100644 index c23928eb606..00000000000 --- a/ghost/member-attribution/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - MemberAttributionService: require('./lib/MemberAttributionService'), - AttributionBuilder: require('./lib/AttributionBuilder'), - UrlTranslator: require('./lib/UrlTranslator'), - ReferrerTranslator: require('./lib/ReferrerTranslator'), - OutboundLinkTagger: require('./lib/OutboundLinkTagger') -}; diff --git a/ghost/member-attribution/package.json b/ghost/member-attribution/package.json deleted file mode 100644 index e363408e93a..00000000000 --- a/ghost/member-attribution/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@tryghost/member-attribution", - "version": "0.0.0", - "repository": "https://github.com/TryGhost/Ghost/tree/main/packages/member-attribution", - "author": "Ghost Foundation", - "private": true, - "main": "index.js", - "scripts": { - "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", - "test": "yarn test:unit", - "lint:code": "eslint *.js lib/ --ext .js --cache", - "lint": "yarn lint:code && yarn lint:test", - "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache" - }, - "devDependencies": { - "c8": "8.0.1", - "mocha": "10.8.2", - "should": "13.2.3", - "sinon": "15.2.0" - }, - "dependencies": { - "@tryghost/domain-events": "0.0.0", - "@tryghost/referrer-parser": "0.1.1", - "@tryghost/string": "0.2.13" - } -} diff --git a/ghost/member-attribution/test/.eslintrc.js b/ghost/member-attribution/test/.eslintrc.js deleted file mode 100644 index 829b601eb0a..00000000000 --- a/ghost/member-attribution/test/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/test' - ] -}; diff --git a/ghost/offers/.eslintrc.js b/ghost/offers/.eslintrc.js deleted file mode 100644 index c9c1bcb5226..00000000000 --- a/ghost/offers/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/node' - ] -}; diff --git a/ghost/offers/index.js b/ghost/offers/index.js deleted file mode 100644 index d6e7e149553..00000000000 --- a/ghost/offers/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/OffersModule'); diff --git a/ghost/offers/package.json b/ghost/offers/package.json deleted file mode 100644 index 71059e50b87..00000000000 --- a/ghost/offers/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@tryghost/members-offers", - "version": "0.0.0", - "private": true, - "author": "Ghost Foundation", - "license": "MIT", - "main": "index.js", - "scripts": { - "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", - "test": "yarn test:unit", - "lint:code": "eslint *.js lib/ --ext .js --cache", - "lint": "yarn lint:code && yarn lint:test", - "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache" - }, - "files": [ - "index.js", - "lib" - ], - "devDependencies": { - "bson-objectid": "2.0.4", - "c8": "8.0.1", - "mocha": "10.8.2", - "should": "13.2.3", - "sinon": "15.2.0" - }, - "dependencies": { - "@tryghost/domain-events": "0.0.0", - "@tryghost/errors": "1.3.7", - "@tryghost/mongo-utils": "0.6.2", - "@tryghost/string": "0.2.13", - "lodash": "4.17.21" - } -} diff --git a/ghost/offers/test/.eslintrc.js b/ghost/offers/test/.eslintrc.js deleted file mode 100644 index 829b601eb0a..00000000000 --- a/ghost/offers/test/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/test' - ] -}; diff --git a/ghost/offers/test/hello.test.js b/ghost/offers/test/hello.test.js deleted file mode 100644 index 0c7be687323..00000000000 --- a/ghost/offers/test/hello.test.js +++ /dev/null @@ -1,10 +0,0 @@ -// Switch these lines once there are useful utils -// const testUtils = require('./utils'); -require('should'); - -describe('Hello world', function () { - it('Runs a test', function () { - // TODO: Write me! - 'hello'.should.eql('hello'); - }); -}); diff --git a/ghost/tiers/.eslintrc.js b/ghost/tiers/.eslintrc.js deleted file mode 100644 index c9c1bcb5226..00000000000 --- a/ghost/tiers/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/node' - ] -}; diff --git a/ghost/tiers/README.md b/ghost/tiers/README.md deleted file mode 100644 index c3eb735197e..00000000000 --- a/ghost/tiers/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Tiers - -' - - -## Usage - - -## Develop - -This is a monorepo package. - -Follow the instructions for the top-level repo. -1. `git clone` this repo & `cd` into it as usual -2. Run `yarn` to install top-level dependencies. - - - -## Test - -- `yarn lint` run just eslint -- `yarn test` run lint and tests - diff --git a/ghost/tiers/index.js b/ghost/tiers/index.js deleted file mode 100644 index 09c61e1de4d..00000000000 --- a/ghost/tiers/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const TierActivatedEvent = require('./lib/TierActivatedEvent'); -const TierArchivedEvent = require('./lib/TierArchivedEvent'); -const TierCreatedEvent = require('./lib/TierCreatedEvent'); -const TierNameChangeEvent = require('./lib/TierNameChangeEvent'); -const TierPriceChangeEvent = require('./lib/TierPriceChangeEvent'); - -module.exports = { - Tier: require('./lib/Tier'), - TiersAPI: require('./lib/TiersAPI'), - InMemoryTierRepository: require('./lib/InMemoryTierRepository'), - TierActivatedEvent, - TierArchivedEvent, - TierCreatedEvent, - TierNameChangeEvent, - TierPriceChangeEvent -}; diff --git a/ghost/tiers/package.json b/ghost/tiers/package.json deleted file mode 100644 index 1f7fe8de9e0..00000000000 --- a/ghost/tiers/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "@tryghost/tiers", - "version": "0.0.0", - "repository": "https://github.com/TryGhost/Ghost/tree/main/packages/tiers", - "author": "Ghost Foundation", - "private": true, - "main": "index.js", - "scripts": { - "dev": "echo \"Implement me!\"", - "test:unit": "NODE_ENV=testing c8 --all --check-coverage --reporter text --reporter cobertura -- mocha --reporter dot './test/**/*.test.js'", - "test": "yarn test:unit", - "lint:code": "eslint *.js lib/ --ext .js --cache", - "lint": "yarn lint:code && yarn lint:test", - "lint:test": "eslint -c test/.eslintrc.js test/ --ext .js --cache" - }, - "files": [ - "index.js", - "lib" - ], - "devDependencies": { - "c8": "8.0.1", - "mocha": "10.8.2" - }, - "dependencies": { - "@tryghost/errors": "1.3.7", - "@tryghost/string": "0.2.13", - "@tryghost/tpl": "0.1.34", - "bson-objectid": "2.0.4" - } -} diff --git a/ghost/tiers/test/.eslintrc.js b/ghost/tiers/test/.eslintrc.js deleted file mode 100644 index 829b601eb0a..00000000000 --- a/ghost/tiers/test/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: ['ghost'], - extends: [ - 'plugin:ghost/test' - ] -}; diff --git a/ghost/tiers/test/index.test.js b/ghost/tiers/test/index.test.js deleted file mode 100644 index 7a5b0c169de..00000000000 --- a/ghost/tiers/test/index.test.js +++ /dev/null @@ -1,18 +0,0 @@ -const assert = require('assert/strict'); -const { - Tier, - TiersAPI, - InMemoryTierRepository -} = require('../index'); - -describe('index.js', function () { - it('Exports Tier', function () { - assert(Tier === require('../lib/Tier')); - }); - it('Exports TiersAPI', function () { - assert(TiersAPI === require('../lib/TiersAPI')); - }); - it('Exports InMemoryTierRepository', function () { - assert(InMemoryTierRepository === require('../lib/InMemoryTierRepository')); - }); -}); diff --git a/yarn.lock b/yarn.lock index 7ddef449f91..0a567a958ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4270,25 +4270,6 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@probe.gl/bench@4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@probe.gl/bench/-/bench-4.1.0.tgz#2a0d1aa58f21874fdfb9cf49b3268cc0c169c773" - integrity sha512-4Jb1B1NHXDayWGzz4oHs3IgymdBq2AVzMUlcE428lELFqGP7nnRMqeGR/PmwElCqvYLJE39Av4QK8E64lUw/cA== - dependencies: - "@probe.gl/log" "4.1.0" - -"@probe.gl/env@4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@probe.gl/env/-/env-4.1.0.tgz#c2af9030a8711f2d98590850aa47a5f58feef211" - integrity sha512-5ac2Jm2K72VCs4eSMsM7ykVRrV47w32xOGMvcgqn8vQdEMF9PRXyBGYEV9YbqRKWNKpNKmQJVi4AHM/fkCxs9w== - -"@probe.gl/log@4.1.0": - version "4.1.0" - resolved "https://registry.yarnpkg.com/@probe.gl/log/-/log-4.1.0.tgz#b5501f96e3aa7f04c75a9800431314d46911cb98" - integrity sha512-r4gRReNY6f+OZEMgfWEXrAE2qJEt8rX0HsDJQXUBMoc+5H47bdB7f/5HBHAmapK8UydwPKL9wCDoS22rJ0yq7Q== - dependencies: - "@probe.gl/env" "4.1.0" - "@radix-ui/number@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674" @@ -7520,7 +7501,7 @@ debug "^4.3.3" lodash "^4.17.21" -"@tryghost/mongo-utils@0.6.2", "@tryghost/mongo-utils@^0.6.2": +"@tryghost/mongo-utils@^0.6.2": version "0.6.2" resolved "https://registry.yarnpkg.com/@tryghost/mongo-utils/-/mongo-utils-0.6.2.tgz#18af1e057aad6876cb7ff61f817df4e90d8055bf" integrity sha512-ewXYg2/EOYNc/ko5zwfvxskYfyLOVjMOPGgRLODJf3jLp9iXK9nfLHOrnAO4Jeh9CLzHm84aWUMaRIFH/XQULg==