Merge branch 'master' into account-import-duplicate-prevention
This commit is contained in:
@@ -58,8 +58,10 @@
|
||||
v-if="!isRegistered"
|
||||
:passkeys-enabled="PASSKEYS_ENABLED"
|
||||
:given-name="givenName"
|
||||
message="Before you can publicly announce a new project or time commitment,
|
||||
a friend needs to register you."
|
||||
:message="
|
||||
`Before you can publicly announce a new project or time commitment, ` +
|
||||
`a friend needs to register you.`
|
||||
"
|
||||
/>
|
||||
|
||||
<!-- Notifications -->
|
||||
@@ -752,6 +754,7 @@ import "leaflet/dist/leaflet.css";
|
||||
|
||||
import { Buffer } from "buffer/";
|
||||
import "dexie-export-import";
|
||||
|
||||
// @ts-expect-error - they aren't exporting it but it's there
|
||||
import { ImportProgress } from "dexie-export-import";
|
||||
import { LeafletMouseEvent } from "leaflet";
|
||||
@@ -813,11 +816,13 @@ import {
|
||||
isApiError,
|
||||
ImportContent,
|
||||
} from "@/interfaces/accountView";
|
||||
import {
|
||||
ProfileService,
|
||||
createProfileService,
|
||||
ProfileData,
|
||||
} from "@/services/ProfileService";
|
||||
// Profile data interface (inlined from ProfileService)
|
||||
interface ProfileData {
|
||||
description: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
includeLocation: boolean;
|
||||
}
|
||||
|
||||
const inputImportFileNameRef = ref<Blob>();
|
||||
|
||||
@@ -916,7 +921,6 @@ export default class AccountViewView extends Vue {
|
||||
imageLimits: ImageRateLimits | null = null;
|
||||
limitsMessage: string = "";
|
||||
|
||||
private profileService!: ProfileService;
|
||||
private notify!: ReturnType<typeof createNotifyHelpers>;
|
||||
|
||||
created() {
|
||||
@@ -926,7 +930,10 @@ export default class AccountViewView extends Vue {
|
||||
// This prevents the "Cannot read properties of undefined (reading 'Default')" error
|
||||
if (L.Icon.Default) {
|
||||
// Type-safe way to handle Leaflet icon prototype
|
||||
const iconDefault = L.Icon.Default.prototype as Record<string, unknown>;
|
||||
const iconDefault = L.Icon.Default.prototype as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
if ("_getIconUrl" in iconDefault) {
|
||||
delete iconDefault._getIconUrl;
|
||||
}
|
||||
@@ -948,17 +955,21 @@ export default class AccountViewView extends Vue {
|
||||
* @throws Will display specific messages to the user based on different errors.
|
||||
*/
|
||||
async mounted(): Promise<void> {
|
||||
this.profileService = createProfileService(
|
||||
this.axios,
|
||||
this.partnerApiServer,
|
||||
);
|
||||
try {
|
||||
await this.initializeState();
|
||||
await this.processIdentity();
|
||||
|
||||
// Profile service logic now inlined - no need for external service
|
||||
logger.debug(
|
||||
"[AccountViewView] Profile logic ready with partnerApiServer:",
|
||||
{
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
},
|
||||
);
|
||||
|
||||
if (this.isRegistered) {
|
||||
try {
|
||||
const profile = await this.profileService.loadProfile(this.activeDid);
|
||||
const profile = await this.loadProfile(this.activeDid);
|
||||
if (profile) {
|
||||
this.userProfileDesc = profile.description;
|
||||
this.userProfileLatitude = profile.latitude;
|
||||
@@ -1411,21 +1422,24 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async checkLimits(): Promise<void> {
|
||||
this.loadingLimits = true;
|
||||
const did = this.activeDid;
|
||||
if (!did) {
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IDENTIFIER;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const did = this.activeDid;
|
||||
|
||||
if (!did) {
|
||||
this.limitsMessage = ACCOUNT_VIEW_CONSTANTS.LIMITS.NO_IDENTIFIER;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$saveUserSettings(did, {
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
webPushServer: this.webPushServer,
|
||||
});
|
||||
|
||||
const imageResp = await fetchImageRateLimits(this.axios, did);
|
||||
const imageResp = await fetchImageRateLimits(
|
||||
this.axios,
|
||||
did,
|
||||
this.DEFAULT_IMAGE_API_SERVER,
|
||||
);
|
||||
|
||||
if (imageResp.status === 200) {
|
||||
this.imageLimits = imageResp.data;
|
||||
@@ -1451,7 +1465,26 @@ export default class AccountViewView extends Vue {
|
||||
} catch (error) {
|
||||
this.limitsMessage =
|
||||
ACCOUNT_VIEW_CONSTANTS.LIMITS.ERROR_RETRIEVING_LIMITS;
|
||||
logger.error("Error retrieving limits: ", error);
|
||||
|
||||
// Enhanced error logging with server context
|
||||
const axiosError = error as {
|
||||
response?: {
|
||||
data?: { error?: { code?: string; message?: string } };
|
||||
status?: number;
|
||||
};
|
||||
};
|
||||
logger.error("[Server Limits] Error retrieving limits:", {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
did: did,
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
errorCode: axiosError?.response?.data?.error?.code,
|
||||
errorMessage: axiosError?.response?.data?.error?.message,
|
||||
httpStatus: axiosError?.response?.status,
|
||||
needsUserMigration: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
// this.notify.error(this.limitsMessage, TIMEOUTS.STANDARD);
|
||||
} finally {
|
||||
this.loadingLimits = false;
|
||||
@@ -1459,24 +1492,70 @@ export default class AccountViewView extends Vue {
|
||||
}
|
||||
|
||||
async onClickSaveApiServer(): Promise<void> {
|
||||
await this.$saveSettings({
|
||||
apiServer: this.apiServerInput,
|
||||
// Enhanced diagnostic logging for claim URL changes
|
||||
const previousApiServer = this.apiServer;
|
||||
const newApiServer = this.apiServerInput;
|
||||
|
||||
logger.debug("[Server Switching] Claim URL change initiated:", {
|
||||
did: this.activeDid,
|
||||
previousServer: previousApiServer,
|
||||
newServer: newApiServer,
|
||||
changeType: "apiServer",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
this.apiServer = this.apiServerInput;
|
||||
|
||||
await this.$saveSettings({
|
||||
apiServer: newApiServer,
|
||||
});
|
||||
this.apiServer = newApiServer;
|
||||
|
||||
// Add this line to save to user-specific settings
|
||||
await this.$saveUserSettings(this.activeDid, {
|
||||
apiServer: this.apiServer,
|
||||
});
|
||||
|
||||
// Log successful server switch
|
||||
logger.debug("[Server Switching] Claim URL change completed:", {
|
||||
did: this.activeDid,
|
||||
previousServer: previousApiServer,
|
||||
newServer: newApiServer,
|
||||
changeType: "apiServer",
|
||||
settingsSaved: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async onClickSavePartnerServer(): Promise<void> {
|
||||
await this.$saveSettings({
|
||||
partnerApiServer: this.partnerApiServerInput,
|
||||
// Enhanced diagnostic logging for partner server changes
|
||||
const previousPartnerServer = this.partnerApiServer;
|
||||
const newPartnerServer = this.partnerApiServerInput;
|
||||
|
||||
logger.debug("[Server Switching] Partner server change initiated:", {
|
||||
did: this.activeDid,
|
||||
previousServer: previousPartnerServer,
|
||||
newServer: newPartnerServer,
|
||||
changeType: "partnerApiServer",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
this.partnerApiServer = this.partnerApiServerInput;
|
||||
|
||||
await this.$saveSettings({
|
||||
partnerApiServer: newPartnerServer,
|
||||
});
|
||||
this.partnerApiServer = newPartnerServer;
|
||||
|
||||
await this.$saveUserSettings(this.activeDid, {
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
|
||||
// Log successful partner server switch
|
||||
logger.debug("[Server Switching] Partner server change completed:", {
|
||||
did: this.activeDid,
|
||||
previousServer: previousPartnerServer,
|
||||
newServer: newPartnerServer,
|
||||
changeType: "partnerApiServer",
|
||||
settingsSaved: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async onClickSavePushServer(): Promise<void> {
|
||||
@@ -1550,7 +1629,6 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
onMapReady(map: L.Map): void {
|
||||
try {
|
||||
logger.debug("Map ready event fired, map object:", map);
|
||||
// doing this here instead of on the l-map element avoids a recentering after a drag then zoom at startup
|
||||
const zoom =
|
||||
this.userProfileLatitude && this.userProfileLongitude ? 12 : 2;
|
||||
@@ -1579,19 +1657,15 @@ export default class AccountViewView extends Vue {
|
||||
// Try to set map ready after component is mounted
|
||||
setTimeout(() => {
|
||||
this.isMapReady = true;
|
||||
logger.debug("Map ready set to true after mounted");
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// Fallback method to handle map initialization failures
|
||||
private handleMapInitFailure(): void {
|
||||
logger.debug("Starting map initialization timeout (5 seconds)");
|
||||
setTimeout(() => {
|
||||
if (!this.isMapReady) {
|
||||
logger.warn("Map failed to initialize, forcing ready state");
|
||||
this.isMapReady = true;
|
||||
} else {
|
||||
logger.debug("Map initialized successfully, timeout not needed");
|
||||
}
|
||||
}, 5000); // 5 second timeout
|
||||
}
|
||||
@@ -1615,7 +1689,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
logger.debug("Saving profile data:", profileData);
|
||||
|
||||
const success = await this.profileService.saveProfile(
|
||||
const success = await this.saveProfileToServer(
|
||||
this.activeDid,
|
||||
profileData,
|
||||
);
|
||||
@@ -1634,7 +1708,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
toggleUserProfileLocation(): void {
|
||||
try {
|
||||
const updated = this.profileService.toggleProfileLocation({
|
||||
const updated = this.toggleProfileLocation({
|
||||
description: this.userProfileDesc,
|
||||
latitude: this.userProfileLatitude,
|
||||
longitude: this.userProfileLongitude,
|
||||
@@ -1679,8 +1753,7 @@ export default class AccountViewView extends Vue {
|
||||
|
||||
async deleteProfile(): Promise<void> {
|
||||
try {
|
||||
logger.debug("Attempting to delete profile for DID:", this.activeDid);
|
||||
const success = await this.profileService.deleteProfile(this.activeDid);
|
||||
const success = await this.deleteProfileFromServer(this.activeDid);
|
||||
if (success) {
|
||||
this.notify.success(ACCOUNT_VIEW_CONSTANTS.SUCCESS.PROFILE_DELETED);
|
||||
this.userProfileDesc = "";
|
||||
@@ -1688,7 +1761,6 @@ export default class AccountViewView extends Vue {
|
||||
this.userProfileLongitude = 0;
|
||||
this.includeUserProfileLocation = false;
|
||||
this.isMapReady = false; // Reset map state
|
||||
logger.debug("Profile deleted successfully, UI state reset");
|
||||
} else {
|
||||
this.notify.error(ACCOUNT_VIEW_CONSTANTS.ERRORS.PROFILE_DELETE_ERROR);
|
||||
}
|
||||
@@ -1734,7 +1806,6 @@ export default class AccountViewView extends Vue {
|
||||
this.isMapReady = false;
|
||||
this.userProfileLatitude = 0;
|
||||
this.userProfileLongitude = 0;
|
||||
logger.debug("Location unchecked, map state reset");
|
||||
} else {
|
||||
// Location checkbox was checked, start map initialization timeout
|
||||
this.isMapReady = false;
|
||||
@@ -1743,7 +1814,6 @@ export default class AccountViewView extends Vue {
|
||||
// Try to set map ready after a short delay to allow Vue to render
|
||||
setTimeout(() => {
|
||||
if (!this.isMapReady) {
|
||||
logger.debug("Setting map ready after timeout");
|
||||
this.isMapReady = true;
|
||||
}
|
||||
}, 1000); // 1 second delay
|
||||
@@ -1796,5 +1866,338 @@ export default class AccountViewView extends Vue {
|
||||
onRecheckLimits() {
|
||||
this.checkLimits();
|
||||
}
|
||||
|
||||
// Inlined profile methods (previously in ProfileService)
|
||||
|
||||
/**
|
||||
* Load user profile from the partner API
|
||||
*/
|
||||
private async loadProfile(did: string): Promise<ProfileData | null> {
|
||||
try {
|
||||
const requestId = `profile_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
logger.debug("[AccountViewView] Loading profile:", {
|
||||
requestId,
|
||||
did,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
|
||||
// Get authentication headers
|
||||
const headers = await getHeaders(did);
|
||||
|
||||
const fullUrl = `${this.partnerApiServer}/api/partner/userProfileForIssuer/${did}`;
|
||||
|
||||
logger.debug("[AccountViewView] Making API request:", {
|
||||
requestId,
|
||||
did,
|
||||
fullUrl,
|
||||
hasAuthHeader: !!headers.Authorization,
|
||||
});
|
||||
|
||||
const response = await this.axios.get(fullUrl, { headers });
|
||||
|
||||
logger.debug("[AccountViewView] Profile loaded successfully:", {
|
||||
requestId,
|
||||
status: response.status,
|
||||
hasData: !!response.data,
|
||||
});
|
||||
|
||||
if (response.data && response.data.data) {
|
||||
const profileData = response.data.data;
|
||||
logger.debug("[AccountViewView] Parsing profile data:", {
|
||||
requestId,
|
||||
locLat: profileData.locLat,
|
||||
locLon: profileData.locLon,
|
||||
description: profileData.description,
|
||||
});
|
||||
|
||||
const result = {
|
||||
description: profileData.description || "",
|
||||
latitude: profileData.locLat || 0,
|
||||
longitude: profileData.locLon || 0,
|
||||
includeLocation: !!(profileData.locLat && profileData.locLon),
|
||||
};
|
||||
|
||||
logger.debug("[AccountViewView] Parsed profile result:", {
|
||||
requestId,
|
||||
result,
|
||||
hasLocation: result.includeLocation,
|
||||
});
|
||||
|
||||
return result;
|
||||
} else {
|
||||
logger.debug("[AccountViewView] No profile data found in response:", {
|
||||
requestId,
|
||||
hasData: !!response.data,
|
||||
hasDataData: !!(response.data && response.data.data),
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error: unknown) {
|
||||
// Handle specific HTTP status codes cleanly to suppress console spam
|
||||
if (error && typeof error === "object" && "response" in error) {
|
||||
const axiosError = error as { response?: { status?: number } };
|
||||
|
||||
if (axiosError.response?.status === 404) {
|
||||
logger.info(
|
||||
"[Profile] No profile found - this is normal for new users",
|
||||
{
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: 404,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (axiosError.response?.status === 400) {
|
||||
logger.warn("[Profile] Bad request - user may not be registered", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: 400,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (
|
||||
axiosError.response?.status === 401 ||
|
||||
axiosError.response?.status === 403
|
||||
) {
|
||||
logger.warn("[Profile] Authentication/authorization issue", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: axiosError.response.status,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Only log full errors for unexpected issues (5xx, network errors, etc.)
|
||||
logger.error("[Profile] Unexpected error loading profile:", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
throw new Error("Failed to load profile");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user profile to the partner API
|
||||
*/
|
||||
private async saveProfileToServer(
|
||||
did: string,
|
||||
profileData: ProfileData,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const requestId = `profile_save_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
logger.debug("[AccountViewView] Saving profile:", {
|
||||
requestId,
|
||||
did,
|
||||
profileData,
|
||||
});
|
||||
|
||||
// Get authentication headers
|
||||
const headers = await getHeaders(did);
|
||||
|
||||
// Prepare payload in the format expected by the partner API
|
||||
const payload = {
|
||||
description: profileData.description,
|
||||
issuerDid: did,
|
||||
...(profileData.includeLocation &&
|
||||
profileData.latitude &&
|
||||
profileData.longitude
|
||||
? {
|
||||
locLat: profileData.latitude,
|
||||
locLon: profileData.longitude,
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
logger.debug("[AccountViewView] Sending payload to server:", {
|
||||
requestId,
|
||||
payload,
|
||||
hasLocation: profileData.includeLocation,
|
||||
});
|
||||
|
||||
const response = await this.axios.post(
|
||||
`${this.partnerApiServer}/api/partner/userProfile`,
|
||||
payload,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
logger.debug("[AccountViewView] Profile saved successfully:", {
|
||||
requestId,
|
||||
status: response.status,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error: unknown) {
|
||||
// Handle specific HTTP status codes cleanly to suppress console spam
|
||||
if (error && typeof error === "object" && "response" in error) {
|
||||
const axiosError = error as { response?: { status?: number } };
|
||||
|
||||
if (axiosError.response?.status === 400) {
|
||||
logger.warn("[Profile] Bad request saving profile", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: 400,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
throw new Error("Invalid profile data");
|
||||
}
|
||||
|
||||
if (
|
||||
axiosError.response?.status === 401 ||
|
||||
axiosError.response?.status === 403
|
||||
) {
|
||||
logger.warn(
|
||||
"[Profile] Authentication/authorization issue saving profile",
|
||||
{
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: axiosError.response.status,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
);
|
||||
throw new Error("Authentication required");
|
||||
}
|
||||
|
||||
if (axiosError.response?.status === 409) {
|
||||
logger.warn("[Profile] Profile conflict - may already exist", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: 409,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
throw new Error("Profile already exists");
|
||||
}
|
||||
}
|
||||
|
||||
// Only log full errors for unexpected issues
|
||||
logger.error("[Profile] Unexpected error saving profile:", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
throw new Error("Failed to save profile");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle profile location visibility
|
||||
*/
|
||||
private toggleProfileLocation(profileData: ProfileData): ProfileData {
|
||||
const includeLocation = !profileData.includeLocation;
|
||||
return {
|
||||
...profileData,
|
||||
latitude: includeLocation ? profileData.latitude : 0,
|
||||
longitude: includeLocation ? profileData.longitude : 0,
|
||||
includeLocation,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear profile location
|
||||
*/
|
||||
private clearProfileLocation(profileData: ProfileData): ProfileData {
|
||||
return {
|
||||
...profileData,
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
includeLocation: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default profile data
|
||||
*/
|
||||
private getDefaultProfile(): ProfileData {
|
||||
return {
|
||||
description: "",
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
includeLocation: false,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user profile from the partner API
|
||||
*/
|
||||
private async deleteProfileFromServer(did: string): Promise<boolean> {
|
||||
try {
|
||||
const requestId = `profile_delete_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
logger.debug("[AccountViewView] Deleting profile:", {
|
||||
requestId,
|
||||
did,
|
||||
});
|
||||
|
||||
// Get authentication headers
|
||||
const headers = await getHeaders(did);
|
||||
|
||||
const response = await this.axios.delete(
|
||||
`${this.partnerApiServer}/api/partner/userProfile/${did}`,
|
||||
{ headers },
|
||||
);
|
||||
|
||||
logger.debug("[AccountViewView] Profile deleted successfully:", {
|
||||
requestId,
|
||||
status: response.status,
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (error: unknown) {
|
||||
// Handle specific HTTP status codes cleanly to suppress console spam
|
||||
if (error && typeof error === "object" && "response" in error) {
|
||||
const axiosError = error as { response?: { status?: number } };
|
||||
|
||||
if (axiosError.response?.status === 404) {
|
||||
logger.info(
|
||||
"[Profile] Profile not found for deletion - may already be deleted",
|
||||
{
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: 404,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
);
|
||||
return true; // Consider it successful if already deleted
|
||||
}
|
||||
|
||||
if (
|
||||
axiosError.response?.status === 401 ||
|
||||
axiosError.response?.status === 403
|
||||
) {
|
||||
logger.warn(
|
||||
"[Profile] Authentication/authorization issue deleting profile",
|
||||
{
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
status: axiosError.response.status,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only log full errors for unexpected issues
|
||||
logger.error("[Profile] Unexpected error deleting profile:", {
|
||||
did,
|
||||
server: this.partnerApiServer,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -124,7 +124,7 @@ import {
|
||||
NOTIFY_CONFIRMATION_RESTRICTION,
|
||||
} from "../constants/notifications";
|
||||
import { Contact } from "../db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
||||
|
||||
import { GiveSummaryRecord, GiveActionClaim } from "../interfaces";
|
||||
import { AgreeActionClaim } from "../interfaces/claims";
|
||||
import {
|
||||
@@ -223,7 +223,7 @@ export default class ContactAmountssView extends Vue {
|
||||
const contact = await this.$getContact(contactDid);
|
||||
this.contact = contact;
|
||||
|
||||
const settings = await this.$getSettings(MASTER_SETTINGS_KEY);
|
||||
const settings = await this.$getMasterSettings();
|
||||
this.activeDid = settings?.activeDid || "";
|
||||
this.apiServer = settings?.apiServer || "";
|
||||
|
||||
|
||||
@@ -568,10 +568,27 @@ export default class HomeView extends Vue {
|
||||
this.isRegistered = true;
|
||||
}
|
||||
} catch (error) {
|
||||
// Enhanced error logging with server context
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
const axiosError = error as {
|
||||
response?: {
|
||||
data?: { error?: { code?: string; message?: string } };
|
||||
status?: number;
|
||||
};
|
||||
};
|
||||
|
||||
logger.warn(
|
||||
"[HomeView Settings Trace] ⚠️ Registration check failed",
|
||||
{
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
error: errorMessage,
|
||||
did: this.activeDid,
|
||||
server: this.apiServer,
|
||||
errorCode: axiosError?.response?.data?.error?.code,
|
||||
errorMessage: axiosError?.response?.data?.error?.message,
|
||||
httpStatus: axiosError?.response?.status,
|
||||
needsUserMigration: true,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -585,8 +602,7 @@ export default class HomeView extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures API server is correctly set for the current platform
|
||||
* For Electron, always use production endpoint regardless of saved settings
|
||||
* Ensures correct API server configuration
|
||||
*
|
||||
* @internal
|
||||
* Called after loading settings to ensure correct API endpoint
|
||||
@@ -594,12 +610,9 @@ export default class HomeView extends Vue {
|
||||
private async ensureCorrectApiServer() {
|
||||
const { DEFAULT_ENDORSER_API_SERVER } = await import("../constants/app");
|
||||
|
||||
if (process.env.VITE_PLATFORM === "electron") {
|
||||
// **CRITICAL FIX**: Always use production API server for Electron
|
||||
// This prevents the capacitor-electron:// protocol from being used for API calls
|
||||
this.apiServer = DEFAULT_ENDORSER_API_SERVER;
|
||||
} else if (!this.apiServer) {
|
||||
// **FIX**: Set default API server for web/development if not already set
|
||||
// Only set default if no user preference exists
|
||||
if (!this.apiServer) {
|
||||
// Set default API server for any platform if not already set
|
||||
this.apiServer = DEFAULT_ENDORSER_API_SERVER;
|
||||
}
|
||||
}
|
||||
@@ -1161,9 +1174,13 @@ export default class HomeView extends Vue {
|
||||
location: fulfillsPlan
|
||||
? { lat: fulfillsPlan.locLat, lon: fulfillsPlan.locLon }
|
||||
: null,
|
||||
inSearchBox: fulfillsPlan
|
||||
? this.latLongInAnySearchBox(fulfillsPlan.locLat, fulfillsPlan.locLon)
|
||||
: null,
|
||||
inSearchBox:
|
||||
fulfillsPlan?.locLat && fulfillsPlan?.locLon
|
||||
? this.latLongInAnySearchBox(
|
||||
fulfillsPlan.locLat,
|
||||
fulfillsPlan.locLon,
|
||||
)
|
||||
: null,
|
||||
finalResult: anyMatch,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ export default class IdentitySwitcherView extends Vue {
|
||||
if (did) {
|
||||
try {
|
||||
const newSettings = await this.$accountSettings(did);
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"[IdentitySwitcher Settings Trace] ✅ New account settings loaded",
|
||||
{
|
||||
did,
|
||||
@@ -252,7 +252,7 @@ export default class IdentitySwitcherView extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
logger.debug(
|
||||
"[IdentitySwitcher Settings Trace] 🔄 Navigating to home to trigger watcher",
|
||||
{
|
||||
newDid: did,
|
||||
|
||||
@@ -110,10 +110,22 @@ export default class NewEditAccountView extends Vue {
|
||||
* @async
|
||||
*/
|
||||
async onClickSaveChanges() {
|
||||
await this.$updateSettings({
|
||||
firstName: this.givenName,
|
||||
lastName: "", // deprecated, pre v 0.1.3
|
||||
});
|
||||
// Get the current active DID to save to user-specific settings
|
||||
const settings = await this.$accountSettings();
|
||||
const activeDid = settings.activeDid;
|
||||
|
||||
if (activeDid) {
|
||||
// Save to user-specific settings for the current identity
|
||||
await this.$saveUserSettings(activeDid, {
|
||||
firstName: this.givenName,
|
||||
});
|
||||
} else {
|
||||
// Fallback to master settings if no active DID
|
||||
await this.$saveSettings({
|
||||
firstName: this.givenName,
|
||||
});
|
||||
}
|
||||
|
||||
this.$router.back();
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ export default class StartView extends Vue {
|
||||
// Load account count for display logic
|
||||
this.numAccounts = await retrieveAccountCount();
|
||||
|
||||
logger.info("[StartView] Component mounted", {
|
||||
logger.debug("[StartView] Component mounted", {
|
||||
hasGivenName: !!this.givenName,
|
||||
accountCount: this.numAccounts,
|
||||
passkeysEnabled: this.PASSKEYS_ENABLED,
|
||||
@@ -221,7 +221,7 @@ export default class StartView extends Vue {
|
||||
* Routes user to new identifier creation flow with seed-based approach
|
||||
*/
|
||||
public onClickNewSeed() {
|
||||
logger.info("[StartView] User selected new seed generation");
|
||||
logger.debug("[StartView] User selected new seed generation");
|
||||
this.$router.push({ name: "new-identifier" });
|
||||
}
|
||||
|
||||
@@ -235,14 +235,14 @@ export default class StartView extends Vue {
|
||||
const keyName =
|
||||
AppString.APP_NAME + (this.givenName ? " - " + this.givenName : "");
|
||||
|
||||
logger.info("[StartView] Initiating passkey registration", {
|
||||
logger.debug("[StartView] Initiating passkey registration", {
|
||||
keyName,
|
||||
hasGivenName: !!this.givenName,
|
||||
});
|
||||
|
||||
await registerSaveAndActivatePasskey(keyName);
|
||||
|
||||
logger.info("[StartView] Passkey registration successful");
|
||||
logger.debug("[StartView] Passkey registration successful");
|
||||
this.$router.push({ name: "account" });
|
||||
} catch (error) {
|
||||
logger.error("[StartView] Passkey registration failed", error);
|
||||
@@ -255,7 +255,7 @@ export default class StartView extends Vue {
|
||||
* Routes user to account import flow for existing seed phrase
|
||||
*/
|
||||
public onClickNo() {
|
||||
logger.info("[StartView] User selected existing seed import");
|
||||
logger.debug("[StartView] User selected existing seed import");
|
||||
this.$router.push({ name: "import-account" });
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ export default class StartView extends Vue {
|
||||
* Routes user to address derivation flow for existing seed
|
||||
*/
|
||||
public onClickDerive() {
|
||||
logger.info("[StartView] User selected address derivation");
|
||||
logger.debug("[StartView] User selected address derivation");
|
||||
this.$router.push({ name: "import-derive" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,13 +91,95 @@
|
||||
name: 'shared-photo',
|
||||
query: { fileName },
|
||||
}"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
|
||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
|
||||
data-testId="fileUploadButton"
|
||||
>
|
||||
Go to Shared Page
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<!-- URL Flow Testing Section -->
|
||||
<div class="mt-8">
|
||||
<h2 class="text-xl font-bold mb-4">URL Flow Testing</h2>
|
||||
<p class="text-sm text-gray-600 mb-3">
|
||||
Test claim and partner server URL flow from initialization to change
|
||||
propagation.
|
||||
</p>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50">
|
||||
<h3 class="font-semibold mb-2">Current URL State</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div>
|
||||
<strong>API Server:</strong>
|
||||
<span class="font-mono">{{ apiServer || "Not Set" }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Partner API Server:</strong>
|
||||
<span class="font-mono">{{ partnerApiServer || "Not Set" }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Active DID:</strong>
|
||||
<span class="font-mono">{{ activeDid || "Not Set" }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Platform:</strong>
|
||||
<span class="font-mono">{{ getCurrentPlatform() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button
|
||||
:class="primaryButtonClasses"
|
||||
:disabled="isUrlTestRunning"
|
||||
@click="testUrlFlow()"
|
||||
>
|
||||
{{ isUrlTestRunning ? "Testing..." : "Test URL Flow" }}
|
||||
</button>
|
||||
|
||||
<button :class="secondaryButtonClasses" @click="changeApiServer()">
|
||||
Change API Server (Test → Prod)
|
||||
</button>
|
||||
|
||||
<button
|
||||
:class="secondaryButtonClasses"
|
||||
@click="changePartnerApiServer()"
|
||||
>
|
||||
Change Partner API Server (Test → Prod)
|
||||
</button>
|
||||
|
||||
<button :class="warningButtonClasses" @click="resetToDefaults()">
|
||||
Reset to Defaults
|
||||
</button>
|
||||
|
||||
<button :class="secondaryButtonClasses" @click="refreshSettings()">
|
||||
Refresh Settings
|
||||
</button>
|
||||
|
||||
<button
|
||||
:class="secondaryButtonClasses"
|
||||
@click="logEnvironmentState()"
|
||||
>
|
||||
Log Environment State
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border border-gray-300 rounded-md bg-gray-50">
|
||||
<h3 class="font-semibold mb-2">URL Flow Test Results</h3>
|
||||
<div class="max-h-64 overflow-y-auto space-y-2">
|
||||
<div
|
||||
v-for="(result, index) in urlTestResults"
|
||||
:key="index"
|
||||
class="p-2 border border-gray-200 rounded text-xs font-mono bg-white"
|
||||
>
|
||||
{{ result }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<h2 class="text-xl font-bold mb-4">Passkeys</h2>
|
||||
See console for results.
|
||||
@@ -326,6 +408,11 @@ export default class Help extends Vue {
|
||||
showEntityGridTest = false;
|
||||
showPlatformServiceTest = false;
|
||||
|
||||
// for URL flow testing
|
||||
isUrlTestRunning = false;
|
||||
urlTestResults: string[] = [];
|
||||
partnerApiServer: string | undefined;
|
||||
|
||||
/**
|
||||
* Computed properties for template streamlining
|
||||
* Eliminates repeated classes and logic in template
|
||||
@@ -534,24 +621,93 @@ export default class Help extends Vue {
|
||||
}
|
||||
|
||||
/**
|
||||
* Component initialization
|
||||
*
|
||||
* Loads user settings and account information for testing interface
|
||||
* Uses PlatformServiceMixin for database access
|
||||
*/
|
||||
async mounted() {
|
||||
const settings = await this.$accountSettings();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.userName = settings.firstName;
|
||||
logger.info(
|
||||
"[TestView] 🚀 Component mounting - starting URL flow tracking",
|
||||
);
|
||||
|
||||
const account = await retrieveAccountMetadata(this.activeDid);
|
||||
if (this.activeDid) {
|
||||
if (account) {
|
||||
this.credIdHex = account.passkeyCredIdHex as string;
|
||||
} else {
|
||||
alert("No account found for DID " + this.activeDid);
|
||||
// Boot-time logging for initial configuration
|
||||
logger.info("[TestView] 🌍 Boot-time configuration detected:", {
|
||||
platform: process.env.VITE_PLATFORM,
|
||||
defaultEndorserApiServer: process.env.VITE_DEFAULT_ENDORSER_API_SERVER,
|
||||
defaultPartnerApiServer: process.env.VITE_DEFAULT_PARTNER_API_SERVER,
|
||||
nodeEnv: process.env.NODE_ENV,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
try {
|
||||
// Track settings loading
|
||||
logger.info("[TestView] 📥 Loading account settings...");
|
||||
const settings = await this.$accountSettings();
|
||||
|
||||
logger.info("[TestView] 📊 Settings loaded:", {
|
||||
activeDid: settings.activeDid,
|
||||
apiServer: settings.apiServer,
|
||||
partnerApiServer: settings.partnerApiServer,
|
||||
isRegistered: settings.isRegistered,
|
||||
firstName: settings.firstName,
|
||||
});
|
||||
|
||||
// Update component state
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.partnerApiServer = settings.partnerApiServer || "";
|
||||
this.userName = settings.firstName;
|
||||
|
||||
logger.info("[TestView] ✅ Component state updated:", {
|
||||
activeDid: this.activeDid,
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
|
||||
// Load account metadata
|
||||
if (this.activeDid) {
|
||||
logger.info(
|
||||
"[TestView] 🔍 Loading account metadata for DID:",
|
||||
this.activeDid,
|
||||
);
|
||||
const account = await retrieveAccountMetadata(this.activeDid);
|
||||
|
||||
if (account) {
|
||||
this.credIdHex = account.passkeyCredIdHex as string;
|
||||
logger.info("[TestView] ✅ Account metadata loaded:", {
|
||||
did: account.did,
|
||||
hasPasskey: !!account.passkeyCredIdHex,
|
||||
passkeyId: account.passkeyCredIdHex,
|
||||
});
|
||||
} else {
|
||||
logger.warn(
|
||||
"[TestView] ⚠️ No account found for DID:",
|
||||
this.activeDid,
|
||||
);
|
||||
alert("No account found for DID " + this.activeDid);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("[TestView] 🎯 Component initialization complete:", {
|
||||
activeDid: this.activeDid,
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
hasPasskey: !!this.credIdHex,
|
||||
platform: this.getCurrentPlatform(),
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
"[TestView] ❌ Error during component initialization:",
|
||||
error,
|
||||
);
|
||||
this.$notify(
|
||||
{
|
||||
group: "error",
|
||||
type: "error",
|
||||
title: "Initialization Error",
|
||||
text: `Failed to initialize component: ${error instanceof Error ? error.message : String(error)}`,
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,5 +980,276 @@ export default class Help extends Vue {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the URL flow from initialization to change propagation.
|
||||
* This simulates the flow where a user's DID is set, and then the
|
||||
* claim and partner server URLs are updated.
|
||||
*/
|
||||
public async testUrlFlow() {
|
||||
this.isUrlTestRunning = true;
|
||||
this.urlTestResults = [];
|
||||
|
||||
try {
|
||||
logger.info("[TestView] 🔬 Starting comprehensive URL flow test");
|
||||
this.addUrlTestResult("🚀 Starting URL flow test...");
|
||||
|
||||
// Test 1: Current state
|
||||
this.addUrlTestResult(`📊 Current State:`);
|
||||
this.addUrlTestResult(` - API Server: ${this.apiServer || "Not Set"}`);
|
||||
this.addUrlTestResult(
|
||||
` - Partner API Server: ${this.partnerApiServer || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(` - Active DID: ${this.activeDid || "Not Set"}`);
|
||||
this.addUrlTestResult(` - Platform: ${this.getCurrentPlatform()}`);
|
||||
|
||||
// Test 2: Load fresh settings
|
||||
this.addUrlTestResult(`\n📥 Testing Settings Loading:`);
|
||||
const startTime = Date.now();
|
||||
const settings = await this.$accountSettings();
|
||||
const loadTime = Date.now() - startTime;
|
||||
|
||||
this.addUrlTestResult(` - Settings loaded in ${loadTime}ms`);
|
||||
this.addUrlTestResult(
|
||||
` - API Server from settings: ${settings.apiServer || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - Partner API Server from settings: ${settings.partnerApiServer || "Not Set"}`,
|
||||
);
|
||||
|
||||
// Test 3: Database query
|
||||
this.addUrlTestResult(`\n💾 Testing Database Query:`);
|
||||
const dbStartTime = Date.now();
|
||||
const dbResult = await this.$dbQuery(
|
||||
"SELECT apiServer, partnerApiServer, activeDid FROM settings WHERE id = ? OR accountDid = ?",
|
||||
[1, this.activeDid || ""],
|
||||
);
|
||||
const dbTime = Date.now() - dbStartTime;
|
||||
|
||||
if (dbResult?.values) {
|
||||
this.addUrlTestResult(` - Database query completed in ${dbTime}ms`);
|
||||
this.addUrlTestResult(
|
||||
` - Raw DB values: ${JSON.stringify(dbResult.values)}`,
|
||||
);
|
||||
} else {
|
||||
this.addUrlTestResult(
|
||||
` - Database query failed or returned no results`,
|
||||
);
|
||||
}
|
||||
|
||||
// Test 4: Environment variables
|
||||
this.addUrlTestResult(`\n🌍 Testing Environment Variables:`);
|
||||
this.addUrlTestResult(
|
||||
` - VITE_PLATFORM: ${import.meta.env.VITE_PLATFORM || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - VITE_DEFAULT_ENDORSER_API_SERVER: ${import.meta.env.VITE_DEFAULT_ENDORSER_API_SERVER || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - VITE_DEFAULT_PARTNER_API_SERVER: ${import.meta.env.VITE_DEFAULT_PARTNER_API_SERVER || "Not Set"}`,
|
||||
);
|
||||
|
||||
// Test 5: Constants
|
||||
this.addUrlTestResult(`\n📋 Testing App Constants:`);
|
||||
this.addUrlTestResult(
|
||||
` - PROD_ENDORSER_API_SERVER: ${AppString.PROD_ENDORSER_API_SERVER}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - PROD_PARTNER_API_SERVER: ${AppString.PROD_PARTNER_API_SERVER}`,
|
||||
);
|
||||
|
||||
// Test 6: Change detection
|
||||
this.addUrlTestResult(`\n🔄 Testing Change Detection:`);
|
||||
const originalApiServer = this.apiServer;
|
||||
const originalPartnerServer = this.partnerApiServer;
|
||||
|
||||
// Simulate a change
|
||||
this.addUrlTestResult(` - Original API Server: ${originalApiServer}`);
|
||||
this.addUrlTestResult(
|
||||
` - Original Partner Server: ${originalPartnerServer}`,
|
||||
);
|
||||
|
||||
// Test 7: Settings update
|
||||
this.addUrlTestResult(`\n💾 Testing Settings Update:`);
|
||||
const testChanges = {
|
||||
apiServer:
|
||||
originalApiServer === "https://api.endorser.ch"
|
||||
? "https://test-api.endorser.ch"
|
||||
: "https://api.endorser.ch",
|
||||
};
|
||||
|
||||
this.addUrlTestResult(
|
||||
` - Attempting to change API Server to: ${testChanges.apiServer}`,
|
||||
);
|
||||
const updateResult = await this.$saveSettings(testChanges);
|
||||
this.addUrlTestResult(
|
||||
` - Update result: ${updateResult ? "Success" : "Failed"}`,
|
||||
);
|
||||
|
||||
// Test 8: Verify change propagation
|
||||
this.addUrlTestResult(`\n✅ Testing Change Propagation:`);
|
||||
const newSettings = await this.$accountSettings();
|
||||
this.addUrlTestResult(
|
||||
` - New API Server from settings: ${newSettings.apiServer || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - Component state API Server: ${this.apiServer || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - Change propagated: ${newSettings.apiServer === this.apiServer ? "Yes" : "No"}`,
|
||||
);
|
||||
|
||||
// Test 9: Revert changes
|
||||
this.addUrlTestResult(`\n🔄 Reverting Changes:`);
|
||||
const revertResult = await this.$saveSettings({
|
||||
apiServer: originalApiServer,
|
||||
});
|
||||
this.addUrlTestResult(
|
||||
` - Revert result: ${revertResult ? "Success" : "Failed"}`,
|
||||
);
|
||||
|
||||
// Test 10: Final verification
|
||||
this.addUrlTestResult(`\n🎯 Final Verification:`);
|
||||
const finalSettings = await this.$accountSettings();
|
||||
this.addUrlTestResult(
|
||||
` - Final API Server: ${finalSettings.apiServer || "Not Set"}`,
|
||||
);
|
||||
this.addUrlTestResult(
|
||||
` - Matches original: ${finalSettings.apiServer === originalApiServer ? "Yes" : "No"}`,
|
||||
);
|
||||
|
||||
this.addUrlTestResult(`\n✅ URL flow test completed successfully!`);
|
||||
logger.info("[TestView] ✅ URL flow test completed successfully");
|
||||
} catch (error) {
|
||||
const errorMsg = `❌ URL flow test failed: ${error instanceof Error ? error.message : String(error)}`;
|
||||
this.addUrlTestResult(errorMsg);
|
||||
logger.error("[TestView] ❌ URL flow test failed:", error);
|
||||
} finally {
|
||||
this.isUrlTestRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a result to the URL test results array.
|
||||
*/
|
||||
private addUrlTestResult(message: string) {
|
||||
this.urlTestResults.push(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the API server to the production URL.
|
||||
*/
|
||||
public changeApiServer() {
|
||||
const currentServer = this.apiServer;
|
||||
const newServer =
|
||||
currentServer === "https://api.endorser.ch"
|
||||
? "https://test-api.endorser.ch"
|
||||
: "https://api.endorser.ch";
|
||||
|
||||
logger.info("[TestView] 🔄 Changing API server:", {
|
||||
from: currentServer,
|
||||
to: newServer,
|
||||
});
|
||||
|
||||
this.apiServer = newServer;
|
||||
this.addUrlTestResult(
|
||||
`API Server changed from ${currentServer} to ${newServer}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the partner API server to the production URL.
|
||||
*/
|
||||
public changePartnerApiServer() {
|
||||
const currentServer = this.partnerApiServer;
|
||||
const newServer =
|
||||
currentServer === "https://partner-api.endorser.ch"
|
||||
? "https://test-partner-api.endorser.ch"
|
||||
: "https://partner-api.endorser.ch";
|
||||
|
||||
logger.info("[TestView] 🔄 Changing partner API server:", {
|
||||
from: currentServer,
|
||||
to: newServer,
|
||||
});
|
||||
|
||||
this.partnerApiServer = newServer;
|
||||
this.addUrlTestResult(
|
||||
`Partner API Server changed from ${currentServer} to ${newServer}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all URL-related settings to their initial values.
|
||||
*/
|
||||
public resetToDefaults() {
|
||||
this.apiServer = AppString.TEST_ENDORSER_API_SERVER;
|
||||
this.partnerApiServer = AppString.TEST_PARTNER_API_SERVER;
|
||||
this.activeDid = "";
|
||||
this.addUrlTestResult("URL Flow Test Results Reset to Defaults.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes settings from the database to verify changes.
|
||||
*/
|
||||
public async refreshSettings() {
|
||||
try {
|
||||
logger.info("[TestView] 🔄 Refreshing settings from database");
|
||||
const settings = await this.$accountSettings();
|
||||
|
||||
// Update component state
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.partnerApiServer = settings.partnerApiServer || "";
|
||||
|
||||
logger.info("[TestView] ✅ Settings refreshed:", {
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
|
||||
this.addUrlTestResult(
|
||||
`Settings refreshed - API Server: ${this.apiServer}, Partner API Server: ${this.partnerApiServer}`,
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error("[TestView] ❌ Error refreshing settings:", error);
|
||||
this.addUrlTestResult(
|
||||
`Error refreshing settings: ${error instanceof Error ? error.message : String(error)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current environment state to the console.
|
||||
*/
|
||||
public logEnvironmentState() {
|
||||
logger.info("[TestView] 🌐 Current Environment State:", {
|
||||
VITE_PLATFORM: import.meta.env.VITE_PLATFORM,
|
||||
VITE_DEFAULT_ENDORSER_API_SERVER: import.meta.env
|
||||
.VITE_DEFAULT_ENDORSER_API_SERVER,
|
||||
VITE_DEFAULT_PARTNER_API_SERVER: import.meta.env
|
||||
.VITE_DEFAULT_PARTNER_API_SERVER,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
activeDid: this.activeDid,
|
||||
apiServer: this.apiServer,
|
||||
partnerApiServer: this.partnerApiServer,
|
||||
});
|
||||
this.$notify({
|
||||
group: "info",
|
||||
type: "info",
|
||||
title: "Environment State Logged",
|
||||
text: "Current environment state logged to console.",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current platform based on the API server.
|
||||
*/
|
||||
public getCurrentPlatform(): string {
|
||||
if (this.apiServer?.includes(AppString.PROD_ENDORSER_API_SERVER)) {
|
||||
return "Production";
|
||||
} else if (this.apiServer?.includes(AppString.TEST_ENDORSER_API_SERVER)) {
|
||||
return "Test";
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user