mirror of
https://github.com/hanzoai/insights.git
synced 2026-10-30 16:15:31 +00:00
716 files rewritten, 30 renamed, same family mapping as the frontend pass.
Held back, and each for a reason rather than by oversight:
db_table values insights_hogfunction, insights_hogflow,
insights_hogfunctiontemplate, hogflow_templates.
Renaming a table is ALTER TABLE, so it ships as a
migration with the raw SQL in nodejs that names it.
hog_invocation_results a Datastore table with Kafka engine tables on it
products/review_hog the module path is the Django app path; moving it
moves app_label and every migration is recorded under
(app_label, name). That is the same history break as
renaming a migration file, one level up.
*/migrations/* five files, untouched
whogho an integration vendor
Checked: 395 of 397 changed Python files compile. The two that do not —
insightsql/database/database.py and temporal/schedule.py — fail identically at
origin/main under the same interpreter, because they use `type X = ...` and
`except*`, which need the 3.13 this repo pins and not the 3.9 doing the check.
Running the check against the original is what told those apart from a real
break.
Co-authored-by: Hanzo Dev <[email protected]>
289 lines
9.0 KiB
TypeScript
289 lines
9.0 KiB
TypeScript
import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea'
|
|
import { forms } from 'kea-forms'
|
|
import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms'
|
|
import { loaders } from 'kea-loaders'
|
|
import { router, urlToAction } from 'kea-router'
|
|
|
|
import { toast } from '@hanzo/elements'
|
|
|
|
import api from 'lib/api'
|
|
import { teamLogic } from 'scenes/teamLogic'
|
|
import { urls } from 'scenes/urls'
|
|
|
|
import { deleteFromTree } from '~/layout/panel-layout/ProjectTree/projectTreeLogic'
|
|
import type { LinkType } from '~/types'
|
|
import { Breadcrumb, ProjectTreeRef } from '~/types'
|
|
|
|
import { linksLogic } from './linksLogic'
|
|
|
|
export type AvailableDomain = 'pscript.gg' | 'postho.gg' | 'script.gg' | 'custom'
|
|
export type DomainDefinition = {
|
|
label: string
|
|
value: AvailableDomain
|
|
soon?: boolean
|
|
paid?: boolean
|
|
}
|
|
|
|
export const AVAILABLE_DOMAINS: DomainDefinition[] = [
|
|
{ label: 'pscript.gg', value: 'pscript.gg' },
|
|
{ label: 'postho.gg', value: 'postho.gg', soon: true },
|
|
{ label: 'script.gg', value: 'script.gg', soon: true },
|
|
{ label: 'Custom (BYOD)', value: 'custom', soon: true, paid: true },
|
|
]
|
|
|
|
export const DEFAULT_SHORT_LINK_DOMAIN = 'pscript.gg'
|
|
export const NEW_LINK: Partial<LinkType> = {
|
|
id: 'new',
|
|
short_link_domain: DEFAULT_SHORT_LINK_DOMAIN,
|
|
short_code: '',
|
|
redirect_url: '',
|
|
description: '',
|
|
}
|
|
|
|
export interface LinkLogicProps {
|
|
/** Either a UUID or "new". */
|
|
id: string
|
|
}
|
|
|
|
// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
|
|
export interface linkLogicValues {
|
|
links: LinkType[] // linksLogic
|
|
currentTeamId: number | null // teamLogic
|
|
breadcrumbs: Breadcrumb[]
|
|
isEditingLink: boolean
|
|
isLinkSubmitting: boolean
|
|
isLinkValid: boolean
|
|
link: LinkType
|
|
linkAllErrors: Record<string, any>
|
|
linkChanged: boolean
|
|
linkErrors: DeepPartialMap<LinkType, ValidationErrorType>
|
|
linkHasErrors: boolean
|
|
linkLoading: boolean
|
|
linkManualErrors: Record<string, any>
|
|
linkMissing: boolean
|
|
linkTouched: boolean
|
|
linkTouches: Record<string, boolean>
|
|
linkValidationErrors: DeepPartialMap<LinkType, ValidationErrorType>
|
|
mode: 'edit' | 'view'
|
|
projectTreeRef: ProjectTreeRef
|
|
showLinkErrors: boolean
|
|
}
|
|
|
|
// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
|
|
export interface linkLogicActions {
|
|
loadLinks: () => any // linksLogic
|
|
loadLinksSuccess: (
|
|
links: LinkType[],
|
|
payload?: any
|
|
) => {
|
|
links: LinkType[]
|
|
payload?: any
|
|
} // linksLogic
|
|
deleteLink: (linkId: LinkType['id']) => {
|
|
linkId: string
|
|
}
|
|
editLink: (editing: boolean) => {
|
|
editing: boolean
|
|
}
|
|
loadLink: () => any
|
|
loadLinkFailure: (
|
|
error: string,
|
|
errorObject?: any
|
|
) => {
|
|
error: string
|
|
errorObject?: any
|
|
}
|
|
loadLinkSuccess: (
|
|
link: LinkType,
|
|
payload?: any
|
|
) => {
|
|
link: LinkType
|
|
payload?: any
|
|
}
|
|
resetLink: (values?: LinkType) => {
|
|
values?: LinkType
|
|
}
|
|
saveLink: (updatedLink: Partial<LinkType>) => Partial<LinkType>
|
|
saveLinkFailure: (
|
|
error: string,
|
|
errorObject?: any
|
|
) => {
|
|
error: string
|
|
errorObject?: any
|
|
}
|
|
saveLinkSuccess: (
|
|
link: LinkType,
|
|
payload?: Partial<LinkType>
|
|
) => {
|
|
link: LinkType
|
|
payload?: Partial<LinkType>
|
|
}
|
|
setLinkManualErrors: (errors: Record<string, any>) => {
|
|
errors: Record<string, any>
|
|
}
|
|
setLinkMissing: () => {
|
|
value: true
|
|
}
|
|
setLinkValue: (
|
|
key: FieldName,
|
|
value: any
|
|
) => {
|
|
name: FieldName
|
|
value: any
|
|
}
|
|
setLinkValues: (values: DeepPartial<LinkType>) => {
|
|
values: DeepPartial<LinkType>
|
|
}
|
|
submitLink: () => {
|
|
value: boolean
|
|
}
|
|
submitLinkFailure: (
|
|
error: Error,
|
|
errors: Record<string, any>
|
|
) => {
|
|
error: Error
|
|
errors: Record<string, any>
|
|
}
|
|
submitLinkRequest: (link: LinkType) => {
|
|
link: LinkType
|
|
}
|
|
submitLinkSuccess: (link: LinkType) => {
|
|
link: LinkType
|
|
}
|
|
touchLinkField: (key: string) => {
|
|
key: string
|
|
}
|
|
}
|
|
|
|
// Generated by kea-typegen. Update if you're an agent, ignore if you're human.
|
|
export interface linkLogicMeta {
|
|
key: string
|
|
__keaTypeGenInternalSelectorTypes: {
|
|
mode: (id: string) => 'edit' | 'view'
|
|
breadcrumbs: (link: LinkType) => Breadcrumb[]
|
|
projectTreeRef: (arg: string) => ProjectTreeRef
|
|
}
|
|
}
|
|
|
|
export type linkLogicType = MakeLogicType<linkLogicValues, linkLogicActions, LinkLogicProps, linkLogicMeta>
|
|
|
|
export const linkLogic = kea<linkLogicType>([
|
|
path(['products', 'links', 'frontend', 'linkLogic']),
|
|
props({} as LinkLogicProps),
|
|
key(({ id }) => id),
|
|
connect(() => ({
|
|
values: [teamLogic, ['currentTeamId'], linksLogic, ['links']],
|
|
actions: [linksLogic, ['loadLinks', 'loadLinksSuccess']],
|
|
})),
|
|
actions({
|
|
setLinkMissing: true,
|
|
editLink: (editing: boolean) => ({ editing }),
|
|
deleteLink: (linkId: LinkType['id']) => ({ linkId }),
|
|
}),
|
|
loaders(({ props, actions }) => ({
|
|
link: {
|
|
loadLink: async () => {
|
|
if (props.id && props.id !== 'new') {
|
|
try {
|
|
const response = await api.links.get(props.id)
|
|
return response
|
|
} catch (error) {
|
|
actions.setLinkMissing()
|
|
throw error
|
|
}
|
|
}
|
|
|
|
return NEW_LINK as LinkType
|
|
},
|
|
saveLink: async (updatedLink: Partial<LinkType>) => {
|
|
const result: LinkType = await (props.id === 'new'
|
|
? api.links.create(updatedLink)
|
|
: api.links.update(props.id, updatedLink))
|
|
if (props.id === 'new') {
|
|
router.actions.replace(urls.link(result.id))
|
|
}
|
|
|
|
return result
|
|
},
|
|
},
|
|
})),
|
|
forms(({ actions, props }) => ({
|
|
link: {
|
|
defaults: { ...NEW_LINK } as LinkType,
|
|
errors: (payload) => ({
|
|
redirect_url: !payload?.redirect_url ? 'Must include a destination url' : undefined,
|
|
short_code: !payload?.short_code ? 'Must include a short code' : undefined,
|
|
}),
|
|
submit: async (payload) => {
|
|
if (props.id && props.id !== 'new') {
|
|
actions.saveLink(payload)
|
|
} else {
|
|
actions.saveLink({ ...payload, _create_in_folder: 'Unfiled/Links' })
|
|
}
|
|
},
|
|
},
|
|
})),
|
|
reducers({
|
|
linkMissing: [false, { setLinkMissing: () => true }],
|
|
isEditingLink: [false, { editLink: (_, { editing }) => editing }],
|
|
}),
|
|
selectors({
|
|
mode: [(_, p) => [p.id], (id: string): 'view' | 'edit' => (id === 'new' ? 'edit' : 'view')],
|
|
breadcrumbs: [
|
|
(s) => [s.link],
|
|
(link: LinkType): Breadcrumb[] => [
|
|
{
|
|
key: 'Link',
|
|
name: 'Link Management',
|
|
path: urls.links(),
|
|
iconType: 'link',
|
|
},
|
|
{
|
|
key: ['Link', link.id || 'new'],
|
|
name: `${link.short_code} (${link.redirect_url})`,
|
|
iconType: 'link',
|
|
},
|
|
],
|
|
],
|
|
projectTreeRef: [
|
|
() => [(_, props: LinkLogicProps) => props.id],
|
|
(id: string): ProjectTreeRef => ({ type: 'link', ref: id === 'new' ? null : String(id) }),
|
|
],
|
|
}),
|
|
listeners(({ actions, values }) => ({
|
|
saveLinkSuccess: ({ link }) => {
|
|
toast.success('Link saved')
|
|
actions.loadLinks()
|
|
link.id && router.actions.replace(urls.link(link.id))
|
|
actions.editLink(false)
|
|
},
|
|
deleteLink: async ({ linkId }) => {
|
|
try {
|
|
await api.links.delete(linkId)
|
|
toast.info('Link deleted. Existing `$linkclick` events will be kept for future analysis')
|
|
actions.loadLinksSuccess(values.links.filter((link) => link.id !== linkId))
|
|
deleteFromTree('link', linkId)
|
|
router.actions.push(urls.links())
|
|
} catch (e) {
|
|
toast.error(`Error deleting Link: ${e}`)
|
|
}
|
|
},
|
|
})),
|
|
urlToAction(({ actions, props }) => ({
|
|
[urls.link(props.id ?? 'new')]: (_, __, ___, { method }) => {
|
|
// If the URL was pushed (user clicked on a link), reset the scene's data.
|
|
// This avoids resetting form fields if you click back/forward.
|
|
if (method === 'PUSH') {
|
|
if (props.id) {
|
|
actions.loadLink()
|
|
}
|
|
}
|
|
},
|
|
})),
|
|
afterMount(({ props, actions }) => {
|
|
if (props.id !== 'new') {
|
|
actions.loadLink()
|
|
}
|
|
}),
|
|
])
|