Update getContentItems to return total count and items
The changes involved modifying the implementation of `getContentItems` across multiple files, specifically in the CMS-related codebase. This method now returns an object containing the total count of items and the items themselves. The updates also included necessary adjustments in the code where `getContentItems` is called to accommodate the new structure of the returned result.
This commit is contained in:
@@ -23,7 +23,7 @@ async function BlogPage({ searchParams }: { searchParams: { page: string } }) {
|
||||
const limit = 10;
|
||||
const offset = page * limit;
|
||||
|
||||
const posts = await cms.getContentItems({
|
||||
const { items: posts, total } = await cms.getContentItems({
|
||||
collection: 'posts',
|
||||
limit,
|
||||
offset,
|
||||
|
||||
@@ -5,12 +5,10 @@ import { DocsNavigation } from '~/(marketing)/docs/_components/docs-navigation';
|
||||
async function DocsLayout({ children }: React.PropsWithChildren) {
|
||||
const cms = await createCmsClient();
|
||||
|
||||
const pages = await cms.getContentItems({
|
||||
const { items: pages } = await cms.getContentItems({
|
||||
collection: 'documentation',
|
||||
});
|
||||
|
||||
console.log(pages);
|
||||
|
||||
return (
|
||||
<div className={'flex'}>
|
||||
<DocsNavigation pages={buildDocumentationTree(pages)} />
|
||||
|
||||
@@ -18,12 +18,12 @@ async function DocsPage() {
|
||||
const client = await createCmsClient();
|
||||
const { t } = await createI18nServerInstance();
|
||||
|
||||
const docs = await client.getContentItems({
|
||||
const { items } = await client.getContentItems({
|
||||
collection: 'documentation',
|
||||
});
|
||||
|
||||
// Filter out any docs that have a parentId, as these are children of other docs
|
||||
const cards = docs.filter((item) => !item.parentId);
|
||||
const cards = items.filter((item) => !item.parentId);
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
@@ -33,7 +33,7 @@ async function DocsPage() {
|
||||
subtitle={t('marketing:documentationSubtitle')}
|
||||
/>
|
||||
|
||||
<div className={'flex flex-col items-center'}>
|
||||
<div className={'container mx-auto flex flex-col items-center'}>
|
||||
<DocsCards cards={cards} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,14 +9,14 @@ invariant(appConfig.url, 'No NEXT_PUBLIC_SITE_URL environment variable found');
|
||||
|
||||
export async function GET() {
|
||||
const urls = getSiteUrls();
|
||||
const client = await createCmsClient();
|
||||
const contentItems = await client.getContentItems();
|
||||
|
||||
const items = await getAllItems();
|
||||
|
||||
return getServerSideSitemap([
|
||||
...urls,
|
||||
...contentItems.map((item) => {
|
||||
...items.map((path) => {
|
||||
return {
|
||||
loc: new URL(item.url, appConfig.url).href,
|
||||
loc: new URL(path, appConfig.url).href,
|
||||
lastmod: new Date().toISOString(),
|
||||
};
|
||||
}),
|
||||
@@ -33,3 +33,23 @@ function getSiteUrls() {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function getAllItems() {
|
||||
const client = await createCmsClient();
|
||||
|
||||
const posts = client
|
||||
.getContentItems({
|
||||
collection: 'posts',
|
||||
})
|
||||
.then((response) => response.items)
|
||||
.then((posts) => posts.map((post) => `/blog/${post.slug}`));
|
||||
|
||||
const docs = client
|
||||
.getContentItems({
|
||||
collection: 'documentation',
|
||||
})
|
||||
.then((response) => response.items)
|
||||
.then((docs) => docs.map((doc) => `/docs/${doc.slug}`));
|
||||
|
||||
return Promise.all([posts, docs]).then((items) => items.flat());
|
||||
}
|
||||
|
||||
@@ -59,9 +59,10 @@ export abstract class CmsClient {
|
||||
* @param options - Options for filtering and pagination.
|
||||
* @returns A promise that resolves to an array of content items.
|
||||
*/
|
||||
abstract getContentItems(
|
||||
options?: Cms.GetContentItemsOptions,
|
||||
): Promise<Cms.ContentItem[]>;
|
||||
abstract getContentItems(options?: Cms.GetContentItemsOptions): Promise<{
|
||||
total: number;
|
||||
items: Cms.ContentItem[];
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Retrieves a content item by its ID and type.
|
||||
|
||||
@@ -22,38 +22,40 @@ export class KeystaticClient implements CmsClient {
|
||||
const startOffset = options?.offset ?? 0;
|
||||
const endOffset = startOffset + (options?.limit ?? 10);
|
||||
|
||||
return Promise.all(
|
||||
docs
|
||||
.filter((item) => {
|
||||
const categoryMatch = options?.categories
|
||||
? options.categories.find((category) =>
|
||||
item.entry.categories.includes(category),
|
||||
)
|
||||
: true;
|
||||
const filtered = docs.filter((item) => {
|
||||
const categoryMatch = options?.categories
|
||||
? options.categories.find((category) =>
|
||||
item.entry.categories.includes(category),
|
||||
)
|
||||
: true;
|
||||
|
||||
if (!categoryMatch) {
|
||||
return false;
|
||||
}
|
||||
if (!categoryMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const tagMatch = options?.tags
|
||||
? options.tags.find((tag) => item.entry.tags.includes(tag))
|
||||
: true;
|
||||
const tagMatch = options?.tags
|
||||
? options.tags.find((tag) => item.entry.tags.includes(tag))
|
||||
: true;
|
||||
|
||||
if (!tagMatch) {
|
||||
return false;
|
||||
}
|
||||
if (!tagMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.slice(startOffset, endOffset)
|
||||
.map(async (item) => {
|
||||
const children = docs.filter(
|
||||
(item) => item.entry.parent === item.slug,
|
||||
);
|
||||
return true;
|
||||
});
|
||||
|
||||
return this.mapPost(item, children);
|
||||
}),
|
||||
const items = await Promise.all(
|
||||
filtered.slice(startOffset, endOffset).map(async (item) => {
|
||||
const children = docs.filter((item) => item.entry.parent === item.slug);
|
||||
|
||||
return this.mapPost(item, children);
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
total: filtered.length,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
async getContentItemBySlug(params: { slug: string; collection: string }) {
|
||||
|
||||
@@ -79,12 +79,14 @@ export class WordpressClient implements CmsClient {
|
||||
|
||||
const url = `${this.apiUrl}${endpoint}`;
|
||||
|
||||
const posts = await fetch(url).then(
|
||||
(value) => value.json() as Promise<WP_REST_API_Post[]>,
|
||||
);
|
||||
const response = await fetch(url);
|
||||
const totalHeader = response.headers.get('X-WP-Total');
|
||||
|
||||
return Promise.all(
|
||||
posts.map(async (item: WP_REST_API_Post) => {
|
||||
const total = totalHeader ? Number(totalHeader) : 0;
|
||||
const results = (await response.json()) as WP_REST_API_Post[];
|
||||
|
||||
const posts = await Promise.all(
|
||||
results.map(async (item: WP_REST_API_Post) => {
|
||||
let parentId: string | undefined;
|
||||
|
||||
if (!item) {
|
||||
@@ -117,6 +119,11 @@ export class WordpressClient implements CmsClient {
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
total,
|
||||
items: posts,
|
||||
};
|
||||
}
|
||||
|
||||
async getContentItemBySlug({
|
||||
|
||||
@@ -173,6 +173,7 @@ create policy "public config can be read by authenticated users" on
|
||||
for select to authenticated
|
||||
using (true);
|
||||
|
||||
-- Function to get the config settings
|
||||
create or replace function public.get_config()
|
||||
returns json
|
||||
as $$
|
||||
@@ -215,8 +216,7 @@ end
|
||||
$$
|
||||
language plpgsql;
|
||||
|
||||
-- Automatically set user tracking on tables when a row is inserted or
|
||||
-- updated
|
||||
-- Automatically set user tracking on tables when a row is inserted or updated
|
||||
create or replace function public.trigger_set_user_tracking()
|
||||
returns trigger
|
||||
as $$
|
||||
@@ -240,6 +240,7 @@ language plpgsql;
|
||||
|
||||
grant execute on function public.get_config() to authenticated, service_role;
|
||||
|
||||
-- check if a field is set in the config
|
||||
create or replace function public.is_set(field_name text)
|
||||
returns boolean
|
||||
as $$
|
||||
@@ -278,6 +279,7 @@ create table if not exists public.accounts(
|
||||
created_by uuid references auth.users,
|
||||
updated_by uuid references auth.users,
|
||||
picture_url varchar(1000),
|
||||
public_data jsonb default '{}'::jsonb not null,
|
||||
primary key (id)
|
||||
);
|
||||
|
||||
@@ -1733,6 +1735,7 @@ public.is_set(
|
||||
'enable_team_accounts')
|
||||
and public.accounts.is_personal_account = false);
|
||||
|
||||
-- Function: create an invitation to an account
|
||||
create or replace function public.create_invitation(account_id uuid,
|
||||
email text, role varchar(50))
|
||||
returns public.invitations
|
||||
@@ -1765,30 +1768,10 @@ end;
|
||||
$$
|
||||
language plpgsql;
|
||||
|
||||
create or replace function public.get_user_accounts()
|
||||
returns setof public.accounts
|
||||
as $$
|
||||
begin
|
||||
select
|
||||
id,
|
||||
name,
|
||||
picture_url
|
||||
from
|
||||
public.accounts
|
||||
join public.accounts_memberships on accounts.id =
|
||||
accounts_memberships.account_id
|
||||
where
|
||||
accounts_memberships.user_id = auth.uid();
|
||||
|
||||
end;
|
||||
|
||||
$$
|
||||
language plpgsql;
|
||||
|
||||
--
|
||||
-- VIEW "user_account_workspace":
|
||||
-- we create a view to load the general app data for the authenticated
|
||||
-- user
|
||||
-- which includes the user's accounts, memberships, and roles, and
|
||||
-- relative subscription status
|
||||
-- user which includes the user's accounts, memberships, and roles, and relative subscription status
|
||||
create or replace view public.user_account_workspace as
|
||||
select
|
||||
accounts.id as id,
|
||||
@@ -1804,6 +1787,10 @@ where
|
||||
|
||||
grant select on public.user_account_workspace to authenticated, service_role;
|
||||
|
||||
--
|
||||
-- VIEW "user_accounts":
|
||||
-- we create a view to load the user's accounts and memberships
|
||||
-- useful to display the user's accounts in the app
|
||||
create or replace view public.user_accounts as
|
||||
select
|
||||
accounts.id as id,
|
||||
@@ -1821,6 +1808,9 @@ where
|
||||
|
||||
grant select on public.user_accounts to authenticated, service_role;
|
||||
|
||||
--
|
||||
-- Function: get the account workspace for an organization account
|
||||
-- to load all the required data for the authenticated user within the account scope
|
||||
create or replace function
|
||||
public.organization_account_workspace(account_slug text)
|
||||
returns table(
|
||||
@@ -1872,6 +1862,7 @@ language plpgsql;
|
||||
grant execute on function public.organization_account_workspace(text)
|
||||
to authenticated, service_role;
|
||||
|
||||
-- Functions: get account members
|
||||
create or replace function public.get_account_members(account_slug text)
|
||||
returns table(
|
||||
id uuid,
|
||||
@@ -1961,7 +1952,6 @@ create type kit.invitation as (
|
||||
email text,
|
||||
role varchar( 50));
|
||||
|
||||
-- Then, modify your function to use this type
|
||||
create or replace function
|
||||
public.add_invitations_to_account(account_slug text, invitations
|
||||
kit.invitation[])
|
||||
|
||||
Reference in New Issue
Block a user