Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Smartlist and misc SDK-related fixes #474

Merged
merged 7 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/build-docker/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ runs:
# Note: until some sort of local caching is implemented, we don't want to cache dependencies
# because the network overhead is too high and eats up lots of time
cache-dependencies: ${{ runner.environment != 'self-hosted' }}
cache-locality: docker

# We only need QEMU when an arm* platform is targeted
- name: Check QEMU requirement
Expand Down
9 changes: 7 additions & 2 deletions .github/actions/setup-rust/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ inputs:
required: false
default: 'true'

cache-locality:
description: 'The locality of the cache, e.g. either local build or docker build'
required: false
default: 'local' # 'local' or 'docker'

runs:
using: composite
steps:
Expand Down Expand Up @@ -35,7 +40,7 @@ runs:
uses: actions/cache/restore@v3
with:
path: core/src/prisma.rs
key: ${{ runner.os }}-prisma-${{ hashFiles('**/schema.prisma') }}
key: ${{ runner.os }}-prisma-${{ hashFiles('**/schema.prisma') }}-${{ inputs.cache-locality }}

- name: Generate Prisma client
if: ${{ steps.cache-prisma-restore.outputs.cache-hit != 'true' }}
Expand All @@ -48,4 +53,4 @@ runs:
uses: actions/cache/save@v4
with:
path: core/src/prisma.rs
key: ${{ runner.os }}-prisma-${{ hashFiles('**/schema.prisma') }}
key: ${{ runner.os }}-prisma-${{ hashFiles('**/schema.prisma') }}-${{ inputs.cache-locality }}
2 changes: 0 additions & 2 deletions core/src/db/filter/smart_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ impl From<&str> for FilterJoin {
#[aliases(SmartFilterSchema = SmartFilter<MediaSmartFilter>)]
pub struct SmartFilter<T> {
pub groups: Vec<FilterGroup<T>>,
#[serde(default)]
pub joiner: FilterJoin,
}

#[generate_smart_filter]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,9 @@ describe('schema', () => {
or: [{ created_at: { lt: new Date('2021-01-01').toISOString() } }],
},
],
joiner: 'OR',
},
id: 'foo',
joiner: 'AND',
joiner: 'OR',
name: 'bar',
visibility: 'PUBLIC',
}),
Expand Down Expand Up @@ -593,7 +592,7 @@ describe('schema', () => {
joiner: 'or',
},
],
joiner: 'and',
joiner: 'or',
},
grouping: 'BY_SERIES',
name: 'bar',
Expand Down Expand Up @@ -667,8 +666,8 @@ describe('schema', () => {
or: [{ created_at: { lt: 42 } }],
},
],
joiner: 'AND',
},
joiner: 'AND',
name: 'bar',
visibility: 'PUBLIC',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export const intoAPIGroup = (input: z.infer<typeof filterGroup>): FilterGroup<Me

export const filterConfig = z.object({
groups: z.array(filterGroup),
joiner: z.enum(['and', 'or', 'not']),
joiner: z.enum(['and', 'or']),
})

export const grouping = z.enum(['BY_BOOKS', 'BY_SERIES', 'BY_LIBRARY'])
Expand Down Expand Up @@ -335,7 +335,7 @@ export const intoForm = ({
description: description || undefined,
filters: {
groups: filters.groups.map(intoFormGroup),
joiner: joiner.toLowerCase() as 'and' | 'or' | 'not',
joiner: joiner.toLowerCase() as 'and' | 'or',
},
grouping: default_grouping || undefined,
name,
Expand All @@ -346,15 +346,15 @@ export const intoAPI = ({
name,
description,
visibility,
filters,
filters: { groups, joiner },
grouping,
}: SmartListFormSchema): CreateOrUpdateSmartList => ({
default_grouping: grouping || null,
description: description || null,
filters: {
groups: filters.groups.map(intoAPIGroup),
joiner: filters.joiner.toUpperCase() as 'AND' | 'OR',
groups: groups.map(intoAPIGroup),
},
joiner: joiner.toUpperCase() as 'AND' | 'OR',
name,
visibility,
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEmailersQuery, useMutation, useSDK } from '@stump/client'
import { CreateOrUpdateEmailer } from '@stump/sdk'
import React, { useEffect } from 'react'
import { useNavigate } from 'react-router'

Expand All @@ -16,7 +17,10 @@ export default function CreateEmailerScene() {
const { emailers } = useEmailersQuery({
suspense: true,
})
const { mutateAsync: createEmailer } = useMutation([sdk.emailer.keys.create], sdk.emailer.create)
const { mutateAsync: createEmailer } = useMutation(
[sdk.emailer.keys.create],
(params: CreateOrUpdateEmailer) => sdk.emailer.create(params),
)

const onSubmit = async ({ name, is_primary, ...config }: CreateOrUpdateEmailerSchema) => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,14 @@ export default function CreateOrUpdateDeviceModal({ isOpen, updatingDevice, onCl
description={t(getKey('name.description'))}
variant="primary"
{...form.register('name')}
ignoreFill
/>
<Input
label={t(getKey('email.label'))}
description={t(getKey('email.description'))}
variant="primary"
{...form.register('email')}
ignoreFill
/>
<CheckBox
label={t(getKey('forbidden.label'))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default function CreateOrUpdateEmailerForm({ emailer, existingNames, onSu
variant="primary"
{...form.register('name')}
errorMessage={errors.name?.message}
ignoreFill
/>

<div className="flex flex-col space-y-4">
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/scenes/smartList/SmartListCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export default function SmartListCard({
return (
<Link to={paths.smartList(id)} className="block w-full">
<Card
className="flex h-32 w-full flex-col gap-y-4 rounded-none border-none bg-background-surface p-4 transition-colors duration-150 first:rounded-t-sm last:rounded-b-sm hover:bg-background-surface-hover/80"
className="flex h-32 w-full flex-col gap-y-4 rounded-lg border-none bg-background-surface p-4 transition-colors duration-150 hover:bg-background-surface-hover/80"
onMouseEnter={() => prefetch({ id })}
>
<div className="flex flex-col gap-y-1.5">
Expand Down
7 changes: 4 additions & 3 deletions packages/browser/src/scenes/smartList/UserSmartListsScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import paths from '@/paths'
import SmartListCard from './SmartListCard'

// TODO: move filter to URL params
// TODO(ui): this scene lowkey ugly

const LOCALE_BASE_KEY = `userSmartListsScene`
const withLocaleKey = (key: string) => `${LOCALE_BASE_KEY}.${key}`
Expand Down Expand Up @@ -80,7 +81,7 @@ export default function UserSmartListsScene() {
// TODO: prolly don't scrollarea on mobile... just scroll on the page
return (
<ScrollArea className="w-full pr-3 md:w-2/3 lg:max-w-xl">
<div className="flex-col divide-y divide-edge">
<div className="flex-col space-y-2">
{smartLists.map((list) => (
<SmartListCard key={list.id} list={list} />
))}
Expand Down Expand Up @@ -123,13 +124,13 @@ export default function UserSmartListsScene() {
<ButtonOrLink
href={paths.smartListCreate()}
variant="ghost"
className="pointer-events-none h-full shrink-0"
disabled
className="h-full shrink-0"
>
{t(withLocaleKey('buttons.createSmartList'))}
</ButtonOrLink>
</div>
</div>

{renderLists()}
</SceneContainer>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export default function SmartListSettingsRouter() {
/**
* A pseudo-patch function which will update the list, mixing what is present in the cache
* with the updates provided.
* Note: It is important to remember the structure of the filters is vastly different from the structure
* of the payload, and so be careful when calling this function that you transform the filters if they are
* present
*/
const patch = useCallback(
(updates: Partial<CreateOrUpdateSmartList>) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,14 @@ export default function BasicSettingsScene() {
[list, name, description],
)

const handleSubmit = useCallback((values: SubSchema) => patch(values), [patch])
const handleSubmit = useCallback(
({ name, description }: SubSchema) =>
patch({
description,
name,
}),
[patch],
)

return (
<Form form={form} onSubmit={handleSubmit} fieldsetClassName="flex flex-col gap-12">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,18 @@ export default function FiltersSettingsScene() {
)

const handleSubmit = useCallback(
(values: SubSchema) =>
({ filters, grouping }: SubSchema) => {
patch(
pick(
intoAPI({
...listAsForm,
...values,
filters,
grouping,
}),
['filters', 'grouping'],
['filters', 'grouping', 'joiner'],
),
),
)
},
[patch, listAsForm],
)

Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/queries/emailers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ export function useCreateEmailDevice() {
mutate: create,
mutateAsync: createAsync,
...restReturn
} = useMutation([sdk.emailer.keys.create], (payload: CreateOrUpdateEmailer) =>
sdk.emailer.create(payload),
} = useMutation([sdk.emailer.keys.createDevice], (payload: CreateOrUpdateEmailDevice) =>
sdk.emailer.createDevice(payload),
)

return {
Expand Down
7 changes: 5 additions & 2 deletions packages/components/src/input/raw/RawInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,18 @@ export const inputVariants = cva(RAW_INPUT_BASE_CLASSES, {
variants: RAW_INPUT_VARIANTS,
})
export type RawInputProps = VariantProps<typeof inputVariants> &
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>
Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & {
ignoreFill?: boolean
}

export const RawInput = React.forwardRef<HTMLInputElement, RawInputProps>(
({ className, variant, size, rounded, isInvalid, contrast, ...props }, ref) => {
({ className, variant, size, rounded, isInvalid, contrast, ignoreFill, ...props }, ref) => {
return (
<input
className={cn(inputVariants({ className, contrast, isInvalid, rounded, size, variant }))}
ref={ref}
{...props}
{...(ignoreFill ? { 'data-1p-ignore': true } : {})}
/>
)
},
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/controllers/emailer-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { createRouteURLHandler } from './utils'
/**
* The root route for the emailer API
*/
const EMAILER_ROUTE = '/emailer'
const EMAILER_ROUTE = '/emailers'
/**
* A helper function to format the URL for emailer API routes with optional query parameters
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/src/controllers/server-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createRouteURLHandler } from './utils'
/**
* The root route for the server API
*/
const SERVER_ROUTE = '/'
const SERVER_ROUTE = ''
/**
* A helper function to format the URL for server API routes with optional query parameters
*/
Expand All @@ -20,15 +20,15 @@ export class ServerAPI extends APIBase {
* Get the version of the Stump instance
*/
async version(): Promise<StumpVersion> {
const { data: version } = await this.axios.get<StumpVersion>(serverURL('version'))
const { data: version } = await this.axios.post<StumpVersion>(serverURL('/version'))
return version
}

/**
* Check for updates to the Stump instance
*/
async checkUpdate(): Promise<UpdateCheck> {
const { data: update } = await this.axios.get<UpdateCheck>(serverURL('update'))
const { data: update } = await this.axios.get<UpdateCheck>(serverURL('/update'))
return update
}

Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/types/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export type SmartListItems = { type: "Books"; items: Media[] } | { type: "Series

export type SmartList = { id: string; name: string; description: string | null; filters: SmartFilter<MediaSmartFilter>; visibility: EntityVisibility; joiner: FilterJoin; default_grouping: SmartListItemGrouping; saved_views: SmartListView[] | null; creator_id?: string | null }

export type SmartFilter<T> = { groups: FilterGroup<T>[]; joiner?: FilterJoin }
export type SmartFilter<T> = { groups: FilterGroup<T>[] }

export type MediaSmartFilter = { name: Filter<string> } | { size: Filter<number> } | { extension: Filter<string> } | { created_at: Filter<string> } | { updated_at: Filter<string> } | { status: Filter<string> } | { path: Filter<string> } | { pages: Filter<number> } | { metadata: MediaMetadataSmartFilter } | { series: SeriesSmartFilter }

Expand Down Expand Up @@ -378,7 +378,7 @@ export type LibraryRelationFilter = { series?: SeriesBaseFilter | null }
export type LibraryFilter = ({ id?: string[]; name?: string[]; path?: string[]; search?: string | null }) & ({ series?: SeriesBaseFilter | null })

/**
* A user-friendly representation of a media's read_progress. This will map to
* A user-friendly representation of a media's `read_progress`. This will map to
* a query condition that will be used to filter the media.
*/
export type ReadStatus = "Unread" | "Reading" | "Completed"
Expand Down
Loading