Skip to content
Open
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
26 changes: 5 additions & 21 deletions packages/apps/app-dashboard/.env.example
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
VITE_VINCENT_DATIL_CONTRACT=0xa3a602F399E9663279cdF63a290101cB6560A87e
VITE_DATIL_PKP_CONTRACT=0x487A9D096BB4B7Ac1520Cb12370e31e677B175EA

VITE_STYTCH_PUBLIC_TOKEN=
VITE_STYTCH_PROJECT_ID=

VITE_LIT_PAYER_SECRET_KEY=
VITE_LIT_RELAY_API_KEY=
VITE_VINCENT_YELLOWSTONE_RPC=https://yellowstone-rpc.litprotocol.com/

VITE_WALLETCONNECT_PROJECT_ID=

VITE_JWT_EXPIRATION_MINUTES=2160

VITE_GAS_BUFFER_DIVISOR=10

VITE_VINCENT_YIELD_APPID=2353287477
VITE_VINCENT_YIELD_MINIMUM_DEPOSIT=50

VITE_LIT_FEATURE_ENV=

VITE_DASHBOARD_URL=http://localhost:5173
VITE_VINCENT_BASE_SEPOLIA_RPC=

VITE_ENV=development

VITE_LIT_TOTAL_MANAGED=340
VITE_TOTAL_APPS=
VITE_TOTAL_ABILITIES=

VITE_FEATURED_APP_IDS=
VITE_OFFICIAL_APP_IDS=
5 changes: 2 additions & 3 deletions packages/apps/app-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@
"@lit-protocol/misc": "^7.2.3",
"@lit-protocol/pkp-ethers": "^7.2.3",
"@lit-protocol/types": "^7.2.3",
"@lit-protocol/vincent-app-sdk": "workspace:*",
"@lit-protocol/vincent-contracts-sdk": "5.1.0",
"@lit-protocol/vincent-registry-sdk": "4.3.0",
"@lit-protocol/vincent-contracts-sdk": "workspace:*",
"@lit-protocol/vincent-registry-sdk": "workspace:*",
"@radix-ui/react-checkbox": "^1.2.3",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-label": "^2.1.7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Button } from '@/components/shared/ui/button';
import { Form } from '@/components/shared/ui/form';
import { StatusMessage } from '@/components/shared/ui/statusMessage';
import { TextField } from '../../form-fields';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';

//const { abilityOwnerDoc } = docSchemas;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Button } from '@/components/shared/ui/button';
import { TextField, LongTextField, ImageUploadField } from '../../form-fields';
import { DeploymentStatusSelectField } from '../../form-fields/array/DeploymentStatusSelectField';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';

const { abilityDoc } = docSchemas;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { StatusMessage } from '@/components/shared/ui/statusMessage';
import { TextField, LongTextField } from '../../form-fields';
import { docSchemas } from '@lit-protocol/vincent-registry-sdk';
import { Ability } from '@/types/developer-dashboard/appTypes';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';

const { abilityVersionDoc } = docSchemas;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { StatusMessage } from '@/components/shared/ui/statusMessage';
import { TextField, LongTextField, SelectField, ImageUploadField } from '../../form-fields';
import { Ability, AbilityVersion } from '@/types/developer-dashboard/appTypes';
import { DeploymentStatusSelectField } from '../../form-fields/array/DeploymentStatusSelectField';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';

const { abilityDoc } = docSchemas;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { AbilityVersion } from '@/types/developer-dashboard/appTypes';
import { LongTextField } from '../../form-fields';
import { docSchemas } from '@lit-protocol/vincent-registry-sdk';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';

const { abilityVersionDoc } = docSchemas;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AlertCircle, CheckCircle } from 'lucide-react';
import { Button } from '@/components/shared/ui/button';
import { theme } from '@/components/user-dashboard/connect/ui/theme';
import { theme } from '@/lib/themeClasses';

interface RefreshAbilityVersionPoliciesFormProps {
onSubmit: () => Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { formatDate } from '@/utils/developer-dashboard/formatDateAndTime';
import { UndeleteAbilityButton } from '@/components/developer-dashboard/ability/wrappers';
import { Ability } from '@/types/developer-dashboard/appTypes';
import { AbilityCard } from '@/components/developer-dashboard/ui/AbilityCard';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { Logo } from '@/components/shared/ui/Logo';

interface AbilitiesListViewProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
import { Ability, AbilityVersion } from '@/types/developer-dashboard/appTypes';
import { Badge } from '@/components/shared/ui/badge';
import { Logo } from '@/components/shared/ui/Logo';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { motion } from 'framer-motion';
import { AppDetail } from '@/components/developer-dashboard/ui/AppDetail';
import { AbilityActionButtons } from '../wrappers/ui/AbilityActionButtons';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ExternalLink } from 'lucide-react';
import { motion } from 'framer-motion';
import { Ability, AbilityVersion } from '@/types/developer-dashboard/appTypes';
import { Badge } from '@/components/shared/ui/badge';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { AbilityVersionActionButtons } from '../wrappers/ui/AbilityVersionActionButtons';
import { AppDetail } from '@/components/developer-dashboard/ui/AppDetail';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Ability, AbilityVersion } from '@/types/developer-dashboard/appTypes';
import { Package, Plus } from 'lucide-react';
import { motion } from 'framer-motion';
import { UndeleteAbilityVersionButton } from '../wrappers/ui/UndeleteAbilityVersionButton';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { VersionCard } from '@/components/developer-dashboard/ui/VersionCard';

interface AbilityVersionsListViewProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/shared/ui/dialog';
import { fonts } from '@/components/user-dashboard/connect/ui/theme';
import { fonts } from '@/lib/themeClasses';

type ViewType =
| 'details'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
DialogHeader,
DialogTitle,
} from '@/components/shared/ui/dialog';
import { fonts } from '@/components/user-dashboard/connect/ui/theme';
import { fonts } from '@/lib/themeClasses';

type ViewType = 'details' | 'edit-version' | 'delete-version' | 'refresh-policies';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Edit, Trash2, Plus, List, ArrowLeftRight } from 'lucide-react';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { ActionButton } from '@/components/developer-dashboard/ui/ActionButton';

interface AbilityActionButtonsProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Edit, Trash2, RefreshCw } from 'lucide-react';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { ActionButton } from '@/components/developer-dashboard/ui/ActionButton';

interface AbilityVersionActionButtonsProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { StatusMessage } from '@/components/shared/ui/statusMessage';
import { getErrorMessage } from '@/utils/developer-dashboard/app-forms';
import Loading from '@/components/shared/ui/Loading';
import { Ability } from '@/types/developer-dashboard/appTypes';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';

interface UndeleteAbilityWrapperProps {
ability: Ability;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,71 @@ import { Button } from '@/components/shared/ui/button';
import {
TextField,
LongTextField,
ArrayField,
ImageUploadField,
} from '@/components/developer-dashboard/form-fields';
import { DeploymentStatusSelectField } from '@/components/developer-dashboard/form-fields/array/DeploymentStatusSelectField';
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
import { theme, fonts } from '@/lib/themeClasses';
import { extractErrorMessage } from '@/utils/developer-dashboard/app-forms';

const { appDoc } = docSchemas;

const {
name,
description,
contactEmail,
appUserUrl,
logo,
redirectUris,
deploymentStatus,
delegateeAddresses,
} = appDoc.shape;
const { appId, name, description, contactEmail, appUrl, logo, deploymentStatus } = appDoc.shape;

// Schema for creating a new app (appId will be generated on-chain)
export const CreateAppSchema = z
.object({
name,
description,
contactEmail,
appUserUrl,
appUrl,
logo,
deploymentStatus,
})
.strict();

// Schema for adding existing on-chain app to registry
export const CreateAppWithIdSchema = z
.object({
appId,
name,
description,
contactEmail,
appUrl,
logo,
redirectUris,
deploymentStatus,
delegateeAddresses,
})
.strict();

export type CreateAppFormData = z.infer<typeof CreateAppSchema>;
export type CreateAppWithIdFormData = z.infer<typeof CreateAppWithIdSchema>;

interface CreateAppFormProps {
onSubmit: (data: CreateAppFormData) => Promise<void>;
onSubmit: (data: CreateAppFormData | CreateAppWithIdFormData) => Promise<void>;
isSubmitting?: boolean;
/**
* When provided, the form is used for recovery: syncing an app that exists
* on-chain but failed to sync to the registry during initial registration.
*/
existingAppId?: number;
onSuccess?: () => void;
}

export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormProps) {
export function CreateAppForm({
onSubmit,
isSubmitting = false,
existingAppId,
onSuccess,
}: CreateAppFormProps) {
const [submitError, setSubmitError] = useState<string | null>(null);
const [submitSuccess, setSubmitSuccess] = useState(false);

const form = useForm<CreateAppFormData>({
resolver: zodResolver(CreateAppSchema),
// Use different schema based on whether we have an existing app ID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An app can be registered only once so what are we exactly checking for the existing appId?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful for when the App registration (in the registry) has failed. There is a recovery flow to create the App document in the event of that happening, but I didn't have the chance to implement a recovery flow for the AppVersionAbility documents.

That would look like reading the app's version 1 from on-chain, reading the IPFS CIDs, and then finding their matches in our database. We'd then create the AppVersionAbility documents on the developer's behalf.

cc: @glitch003 (just to let you know)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you create a ticket for the remaining task @awisniew207

const schema = existingAppId ? CreateAppWithIdSchema : CreateAppSchema;

const form = useForm<CreateAppFormData | CreateAppWithIdFormData>({
resolver: zodResolver(schema),
defaultValues: {
redirectUris: [''],
delegateeAddresses: [''],
...(existingAppId && { appId: existingAppId }),
deploymentStatus: 'dev',
},
});
Expand All @@ -74,12 +90,15 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP
formState: { errors },
} = form;

const handleFormSubmit = async (data: CreateAppFormData) => {
const handleFormSubmit = async (data: CreateAppFormData | CreateAppWithIdFormData) => {
setSubmitError(null);
setSubmitSuccess(false);
try {
await onSubmit(data);
setSubmitSuccess(true);
if (onSuccess) {
onSuccess();
}
} catch (error) {
console.error('Failed to create app:', error);
setSubmitError(extractErrorMessage(error, 'Failed to create app'));
Expand Down Expand Up @@ -129,10 +148,10 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP
/>

<TextField
name="appUserUrl"
name="appUrl"
register={register}
error={errors.appUserUrl?.message}
label="App User URL"
error={errors.appUrl?.message}
label="App URL"
placeholder="https://yourapp.com"
required
/>
Expand Down Expand Up @@ -163,31 +182,6 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP
</div>
</div>

{/* Full Width Fields */}
<div className="space-y-6">
<ArrayField
name="redirectUris"
register={register}
error={errors.redirectUris?.message}
errors={errors}
control={control}
label="Redirect URIs"
placeholder="https://yourapp.com/callback"
required
/>

<ArrayField
name="delegateeAddresses"
register={register}
error={errors.delegateeAddresses?.message}
errors={errors}
control={control}
label="Delegatee Addresses"
placeholder="0x1234567890123456789012345678901234567890"
required
/>
</div>

{/* Status Messages */}
{submitError && (
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800">
Expand All @@ -200,7 +194,9 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP
<div className="flex items-center gap-2 px-3 py-2 rounded-lg bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800">
<CheckCircle className="h-4 w-4 text-green-600 dark:text-green-400 flex-shrink-0" />
<span className="text-sm text-green-600 dark:text-green-400">
App created successfully!
{existingAppId
? 'App synced to registry successfully!'
: 'App created successfully!'}
</span>
</div>
)}
Expand All @@ -211,7 +207,13 @@ export function CreateAppForm({ onSubmit, isSubmitting = false }: CreateAppFormP
style={{ backgroundColor: theme.brandOrange }}
disabled={isSubmitting}
>
{isSubmitting ? 'Creating App...' : 'Create App'}
{isSubmitting
? existingAppId
? 'Syncing to Registry...'
: 'Creating App...'
: existingAppId
? 'Sync to Registry'
: 'Create App'}
</Button>
</div>
</form>
Expand Down
Loading