Compare commits

..

10 Commits

15 changed files with 300 additions and 102 deletions

View File

@@ -9,7 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.1.6] ## [0.1.6] - 2023.12.17
### Added
- Infinite scroll on home page
### Changed
- UI improvements
- Show web-push subscription info
- Icon
## [0.1.5] - 2023.12.09 - 9c36bb509a9bae9bb3306d3bd9eeb144b67aa8ad ## [0.1.5] - 2023.12.09 - 9c36bb509a9bae9bb3306d3bd9eeb144b67aa8ad

View File

@@ -26,13 +26,15 @@ If you are deploying in a subdirectory, add it to `publicPath` in vue.config.js,
...to make sure the service worker scripts are in proper form ...to make sure the service worker scripts are in proper form
* Update the CHANGELOG.md & the version in package.json, run `npm install`, and commit. Tag wth the new version: `git tag 0.1.0` * Update the CHANGELOG.md & the version in package.json, run `npm install`, and commit.
* Tag wth the new version: `git tag 0.1.0`. Increment version, add "-beta", `npm install`, and commit.
* If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD. * If production, change src/constants/app.ts DEFAULT_*_SERVER to be PROD.
* `npm run build` * `npm run build`
* Revert src/constants/app.ts & change version to "-beta" * Revert src/constants/app.ts
* `cp sw_scripts/[ns]* dist/` * `cp sw_scripts/[ns]* dist/`

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "TimeSafari", "name": "TimeSafari",
"version": "0.1.6-beta", "version": "0.1.7-beta",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "TimeSafari", "name": "TimeSafari",
"version": "0.1.6-beta", "version": "0.1.7-beta",
"dependencies": { "dependencies": {
"@ethersproject/hdnode": "^5.7.0", "@ethersproject/hdnode": "^5.7.0",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",

View File

@@ -1,6 +1,6 @@
{ {
"name": "TimeSafari", "name": "TimeSafari",
"version": "0.1.6-beta", "version": "0.1.7-beta",
"private": true, "private": true,
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",

View File

@@ -2,30 +2,26 @@
tasks: tasks:
- 08 notifications : - 08 notifications :
- get it to work on Android - get it to work on Android - background data in apps
- get it to work on iOS - get it to work on iOS
- lock down regenerate_vapid endpoint (so only we admins can do it on demand)
- make the app behave correctly when App Notifications are turned off - make the app behave correctly when App Notifications are turned off
- remove sleep in py-push-server app.py?
- write troubleshooting docs for notifications - write troubleshooting docs for notifications
- make the "App Notifications" toggle on when they turn notifications on - hide the "App Notifications" toggle when they switch notifications
- make the "App Notifications" toggle off when they turn notifications off - prompt user to install on their home screen https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps
- in py-push-server, when sending a push to a subscriber and we get on a 410 "error #106", delete the subscription record - warn if they're using the web (android only?)
- https://gitea.anomalistdesign.com/trent_larson/py-push-server/pulls/3/files https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getInstalledRelatedApps
- remove "notification push server" advanced setting since it only makes sense on the current domain https://web.dev/articles/get-installed-related-apps
- prompt user to install on their home screen - add windows & mac help at OS & browser level
- back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity - back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity
- fix the projects on /discover to show the issuer (currently all "Someone Anonymous") - fix the projects on /discover to show the issuer (currently all "Someone Anonymous")
- .3 bug - make or edit a project, choose "Include location", and see the map display shows on top of the bottom icons assignee-group:ui - .3 bug - make or edit a project, choose "Include location", and see the map display shows on top of the bottom icons assignee-group:ui
- Got error adding on Firefox user #0 as contact for themselves
- .5 Add infinite scroll to gifts on the home page
- .5 If notifications are not enabled, add message to front page with link/button to enable - .5 If notifications are not enabled, add message to front page with link/button to enable
- 01 server - show all claim details when issued by the issuer - 01 server - show all claim details when issued by the issuer
- add note after contact addition that they can see your info
- enhance help page instructions for debugging - enhance help page instructions for debugging
- add way to test quickly a push notification - add way to test quickly a push notification
- help instructions for PWA install problems (secret failed, must reinstall) - help instructions for PWA install problems (secret failed, must reinstall)
@@ -50,10 +46,10 @@ tasks:
- Other features - donation vs give, show offers, show give & outstanding totals, show network view, restrict registration, connect to contacts - Other features - donation vs give, show offers, show give & outstanding totals, show network view, restrict registration, connect to contacts
blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time
- 01 send visibility signal as a VC and store it
- remove 'rowid' references (that are sqlite-specific) - remove 'rowid' references (that are sqlite-specific)
- make identicons for contacts into more-memorable faces (and maybe change project identicons, too) - make identicons for contacts into more-memorable faces (and maybe change project identicons, too)
- 01 make the prod build copy the sw_scripts - 01 make the prod build copy the sw_scripts
- 01 send visibility signal as a VC and store it
- .5 Add start date to project - .5 Add start date to project
- .3 check that Android shows "back" buttons on screens without bottom tray - .3 check that Android shows "back" buttons on screens without bottom tray
- .1 Make give description text box into something that expands as they type? - .1 Make give description text box into something that expands as they type?

View File

@@ -0,0 +1,58 @@
<template>
<div class="text-center text-red-500">{{ message }}</div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-facing-decorator";
import { db } from "@/db/index";
import { MASTER_SETTINGS_KEY } from "@/db/tables/settings";
import { AppString } from "@/constants/app";
interface Notification {
group: string;
type: string;
title: string;
text: string;
}
@Component
export default class TopMessage extends Vue {
$notify!: (notification: Notification, timeout?: number) => void;
@Prop selected = "";
message = "";
async mounted() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
if (
settings?.warnIfTestServer &&
window.location.hostname !== AppString.PROD_TIME_SAFARI_SERVER_HOST
) {
const didPrefix = settings.activeDid?.slice(11, 14);
this.message = "You're linked to a test server, user " + didPrefix;
} else if (
settings?.warnIfProdServer &&
window.location.hostname === AppString.PROD_TIME_SAFARI_SERVER_HOST
) {
const didPrefix = settings.activeDid?.slice(1, 14);
this.message =
"You're linked to the production server, user " + didPrefix;
}
} catch (err: unknown) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Detecting Server",
text: JSON.stringify(err),
},
10000,
);
}
}
}
</script>

View File

@@ -6,12 +6,16 @@
export enum AppString { export enum AppString {
APP_NAME = "Time Safari", APP_NAME = "Time Safari",
PROD_TIME_SAFARI_SERVER_HOST = "timesafari.app",
PROD_TIME_SAFARI_SERVER = "https://" + PROD_TIME_SAFARI_SERVER_HOST,
PROD_ENDORSER_API_SERVER = "https://api.endorser.ch", PROD_ENDORSER_API_SERVER = "https://api.endorser.ch",
TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch", TEST_ENDORSER_API_SERVER = "https://test-api.endorser.ch",
LOCAL_ENDORSER_API_SERVER = "http://localhost:3000", LOCAL_ENDORSER_API_SERVER = "http://localhost:3000",
DEFAULT_ENDORSER_API_SERVER = TEST_ENDORSER_API_SERVER, DEFAULT_ENDORSER_API_SERVER = TEST_ENDORSER_API_SERVER,
// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values
PROD_PUSH_SERVER = "https://timesafari.app", PROD_PUSH_SERVER = "https://timesafari.app",
TEST1_PUSH_SERVER = "https://test.timesafari.app", TEST1_PUSH_SERVER = "https://test.timesafari.app",
TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com", TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com",

View File

@@ -45,8 +45,5 @@ db.on("populate", () => {
db.settings.add({ db.settings.add({
id: MASTER_SETTINGS_KEY, id: MASTER_SETTINGS_KEY,
apiServer: AppString.DEFAULT_ENDORSER_API_SERVER, apiServer: AppString.DEFAULT_ENDORSER_API_SERVER,
// remember that things you add from now on aren't automatically in the DB for old users
webPushServer: AppString.DEFAULT_PUSH_SERVER,
}); });
}); });

View File

@@ -12,15 +12,17 @@ export type BoundingBox = {
* Settings type encompasses user-specific configuration details. * Settings type encompasses user-specific configuration details.
*/ */
export type Settings = { export type Settings = {
id: number; // Only one entry using MASTER_SETTINGS_KEY id: number; // Only one entry, keyed with MASTER_SETTINGS_KEY
activeDid?: string; // Active Decentralized ID activeDid?: string; // Active Decentralized ID
apiServer?: string; // API server URL apiServer?: string; // API server URL
firstName?: string; // User's first name firstName?: string; // User's first name
lastName?: string; // deprecated - put all names in firstName
lastViewedClaimId?: string; // Last viewed claim ID
lastNotifiedClaimId?: string; // Last notified claim ID
isRegistered?: boolean; isRegistered?: boolean;
webPushServer?: string; // Web Push server URL lastName?: string; // deprecated - put all names in firstName
lastNotifiedClaimId?: string; // Last notified claim ID
lastViewedClaimId?: string; // Last viewed claim ID
reminderTime?: number; // Time in milliseconds since UNIX epoch for reminders
reminderOn?: boolean; // Toggle to enable or disable reminders
// Array of named search boxes defined by bounding boxes // Array of named search boxes defined by bounding boxes
searchBoxes?: Array<{ searchBoxes?: Array<{
@@ -30,8 +32,9 @@ export type Settings = {
showContactGivesInline?: boolean; // Display contact inline or not showContactGivesInline?: boolean; // Display contact inline or not
vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push vapid?: string; // VAPID (Voluntary Application Server Identification) field for web push
reminderTime?: number; // Time in milliseconds since UNIX epoch for reminders warnIfProdServer?: boolean; // Warn if using a production server
reminderOn?: boolean; // Toggle to enable or disable reminders warnIfTestServer?: boolean; // Warn if using a testing server
webPushServer?: string; // Web Push server URL
}; };
/** /**

View File

@@ -1,5 +1,7 @@
<template> <template>
<QuickNav selected="Profile"></QuickNav> <QuickNav selected="Profile"></QuickNav>
<TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Heading --> <!-- Heading -->
@@ -104,6 +106,7 @@
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"> <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8">
<label <label
v-if="notificationUnchanged"
for="toggleNotifications" for="toggleNotifications"
class="flex items-center justify-between cursor-pointer" class="flex items-center justify-between cursor-pointer"
@click=" @click="
@@ -143,6 +146,10 @@
></div> ></div>
</div> </div>
</label> </label>
<label v-else>
Notification status may have changed. Revisit this page to see the
latest setting.
</label>
</div> </div>
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3> <h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
@@ -215,7 +222,7 @@
<div v-if="showAdvanced"> <div v-if="showAdvanced">
<p class="text-rose-600 mb-8"> <p class="text-rose-600 mb-8">
Beware: the features here can be confusing and even change data in ways Beware: the features here can be confusing and even change data in ways
you do not expect. But we support your freedoms! you do not expect. But we support your freedom!
</p> </p>
<!-- Deep Identity Details --> <!-- Deep Identity Details -->
@@ -357,6 +364,46 @@
</button> </button>
</div> </div>
<label
for="toggleProdWarningMessage"
class="flex items-center justify-between cursor-pointer my-4"
@click="toggleProdWarning"
>
<!-- label -->
<h2>Show warning if on prod server</h2>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input type="checkbox" v-model="warnIfProdServer" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</label>
<label
for="toggleTestWarningMessage"
class="flex items-center justify-between cursor-pointer my-4"
@click="toggleTestWarning"
>
<!-- label -->
<h2>Show warning if on test server</h2>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input type="checkbox" v-model="warnIfTestServer" class="sr-only" />
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</label>
<div class="flex py-4"> <div class="flex py-4">
<h2 class="text-slate-500 text-sm font-bold mb-2"> <h2 class="text-slate-500 text-sm font-bold mb-2">
Notification Push Server Notification Push Server
@@ -408,6 +455,7 @@ import { Component, Vue } from "vue-facing-decorator";
import { useClipboard } from "@vueuse/core"; import { useClipboard } from "@vueuse/core";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { AppString } from "@/constants/app"; import { AppString } from "@/constants/app";
import { db, accountsDB } from "@/db/index"; import { db, accountsDB } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
@@ -432,7 +480,7 @@ interface IAccount {
derivationPath: string; derivationPath: string;
} }
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav, TopMessage } })
export default class AccountViewView extends Vue { export default class AccountViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
@@ -444,6 +492,7 @@ export default class AccountViewView extends Vue {
derivationPath = ""; derivationPath = "";
givenName = ""; givenName = "";
isRegistered = false; isRegistered = false;
notificationUnchanged = true;
numAccounts = 0; numAccounts = 0;
publicHex = ""; publicHex = "";
publicBase64 = ""; publicBase64 = "";
@@ -462,6 +511,8 @@ export default class AccountViewView extends Vue {
showAdvanced = false; showAdvanced = false;
subscription: PushSubscription | null = null; subscription: PushSubscription | null = null;
warnIfProdServer = false;
warnIfTestServer = false;
private isSubscribed = false; private isSubscribed = false;
get toggleNotifications() { get toggleNotifications() {
@@ -469,6 +520,63 @@ export default class AccountViewView extends Vue {
} }
set toggleNotifications(value) { set toggleNotifications(value) {
this.isSubscribed = value; this.isSubscribed = value;
this.notificationUnchanged = false;
}
/**
* Async function executed when the component is created.
* Initializes the component's state with values from the database,
* handles identity-related tasks, and checks limitations.
*
* @throws Will display specific messages to the user based on different errors.
*/
async created() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
// Initialize component state with values from the database or defaults
this.initializeState(settings);
// Get and process the identity
const identity = await this.getIdentity(this.activeDid);
if (identity) {
this.processIdentity(identity);
}
} catch (err: unknown) {
this.handleError(err);
}
}
async mounted() {
try {
const registration = await navigator.serviceWorker.ready;
this.subscription = await registration.pushManager.getSubscription();
this.toggleNotifications = !!this.subscription;
} catch (error) {
console.error("Mount error:", error);
this.toggleNotifications = false;
}
}
/**
* Initializes component state with values from the database or defaults.
* @param {SettingsType} settings - Object containing settings from the database.
*/
initializeState(settings: Settings | undefined) {
this.activeDid = (settings?.activeDid as string) || "";
this.apiServer = (settings?.apiServer as string) || "";
this.apiServerInput = (settings?.apiServer as string) || "";
this.givenName =
(settings?.firstName || "") +
(settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
this.isRegistered = !!settings?.isRegistered;
this.showContactGives = !!settings?.showContactGivesInline;
this.warnIfProdServer = !!settings?.warnIfProdServer;
this.warnIfTestServer = !!settings?.warnIfTestServer;
this.webPushServer = (settings?.webPushServer as string) || "";
this.webPushServerInput = (settings?.webPushServer as string) || "";
} }
public async getIdentity(activeDid: string): Promise<IIdentifier | null> { public async getIdentity(activeDid: string): Promise<IIdentifier | null> {
@@ -536,6 +644,16 @@ export default class AccountViewView extends Vue {
this.updateShowContactAmounts(); this.updateShowContactAmounts();
} }
toggleProdWarning() {
this.warnIfProdServer = !this.warnIfProdServer;
this.updateWarnIfProdServer(this.warnIfProdServer);
}
toggleTestWarning() {
this.warnIfTestServer = !this.warnIfTestServer;
this.updateWarnIfTestServer(this.warnIfTestServer);
}
readableTime(timeStr: string) { readableTime(timeStr: string) {
return timeStr.substring(0, timeStr.indexOf("T")); return timeStr.substring(0, timeStr.indexOf("T"));
} }
@@ -545,60 +663,6 @@ export default class AccountViewView extends Vue {
this.numAccounts = await accountsDB.accounts.count(); this.numAccounts = await accountsDB.accounts.count();
} }
/**
* Async function executed when the component is created.
* Initializes the component's state with values from the database,
* handles identity-related tasks, and checks limitations.
*
* @throws Will display specific messages to the user based on different errors.
*/
async created() {
try {
await db.open();
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
// Initialize component state with values from the database or defaults
this.initializeState(settings);
// Get and process the identity
const identity = await this.getIdentity(this.activeDid);
if (identity) {
this.processIdentity(identity);
}
} catch (err: unknown) {
this.handleError(err);
}
}
async mounted() {
try {
const registration = await navigator.serviceWorker.ready;
this.subscription = await registration.pushManager.getSubscription();
this.toggleNotifications = !!this.subscription;
} catch (error) {
console.error("Mount error:", error);
this.toggleNotifications = false;
}
}
/**
* Initializes component state with values from the database or defaults.
* @param {SettingsType} settings - Object containing settings from the database.
*/
initializeState(settings: Settings | undefined) {
this.activeDid = (settings?.activeDid as string) || "";
this.apiServer = (settings?.apiServer as string) || "";
this.apiServerInput = (settings?.apiServer as string) || "";
this.givenName =
(settings?.firstName || "") +
(settings?.lastName ? ` ${settings.lastName}` : ""); // pre v 0.1.3
this.isRegistered = !!settings?.isRegistered;
this.webPushServer = (settings?.webPushServer as string) || "";
this.webPushServerInput = (settings?.webPushServer as string) || "";
this.showContactGives = !!settings?.showContactGivesInline;
}
/** /**
* Processes the identity and updates the component's state. * Processes the identity and updates the component's state.
* @param {IdentityType} identity - Object containing identity information. * @param {IdentityType} identity - Object containing identity information.
@@ -672,6 +736,52 @@ export default class AccountViewView extends Vue {
} }
} }
public async updateWarnIfProdServer(newSetting: boolean) {
try {
await db.open();
db.settings.update(MASTER_SETTINGS_KEY, {
warnIfProdServer: newSetting,
});
} catch (err) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Updating Prod Warning",
text: "Clear your cache and start over (after data backup).",
},
-1,
);
console.error(
"Telling user to clear cache after contact setting update because:",
err,
);
}
}
public async updateWarnIfTestServer(newSetting: boolean) {
try {
await db.open();
db.settings.update(MASTER_SETTINGS_KEY, {
warnIfTestServer: newSetting,
});
} catch (err) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error Updating Test Warning",
text: "Clear your cache and start over (after data backup).",
},
-1,
);
console.error(
"Telling user to clear cache after contact setting update because:",
err,
);
}
}
/** /**
* Asynchronously exports the database into a downloadable JSON file. * Asynchronously exports the database into a downloadable JSON file.
* *

View File

@@ -19,9 +19,9 @@
<!-- Details --> <!-- Details -->
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4"> <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
<div> <div>
<div class="block pb-4 flex gap-4 overflow-hidden"> <div class="block flex gap-4 overflow-hidden">
<div class="overflow-hidden"> <div class="overflow-hidden">
<h2 class="text-xl">{{ veriClaim.id }}</h2> <h2 class="text-md font-bold">{{ veriClaim.id }}</h2>
<div class="text-sm"> <div class="text-sm">
<div> <div>
{{ veriClaim.claimType }} {{ veriClaim.claimType }}
@@ -45,7 +45,7 @@
</div> </div>
<div> <div>
<h2 class="font-bold text-2xl">Confirmations</h2> <h2 class="font-bold uppercase text-xl mt-8 mb-2">Confirmations</h2>
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span> <span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
<span v-else-if="totalConfirmers() === 1"> <span v-else-if="totalConfirmers() === 1">
@@ -136,22 +136,24 @@
</div> </div>
<div> <div>
<h2 class="font-bold text-2xl mt-8">Claim</h2> <h2 class="font-bold uppercase text-xl mt-8 mb-2">Claim</h2>
<pre>{{ util.inspect(veriClaim, false, null) }}</pre> <pre class="text-sm overflow-x-scroll px-4 py-3 bg-slate-100 rounded-md">
{{ util.inspect(veriClaim, false, null) }}
</pre>
</div> </div>
<h2 class="font-bold text-2xl mt-8">Full Claim</h2> <h2 class="font-bold uppercase text-xl mt-8 mb-2">Full Claim</h2>
<p> <p class="mb-4">
The full claim includes the claim as it was originally issued, including The full claim includes the claim as it was originally issued, including
the signature (ie. the proof of issuance by that person). the signature (ie. the proof of issuance by that person).
</p> </p>
<div v-if="!fullClaim"> <div v-if="!fullClaim">
<div v-if="fullClaimMessage"> <p v-if="fullClaimMessage" class="mb-4">
{{ fullClaimMessage }} {{ fullClaimMessage }}
</div> </p>
<button <button
v-else v-else
class="bg-blue-600 text-white mt-4 px-4 py-2 rounded-md mb-4" class="block w-full text-center text-md uppercase bg-blue-600 text-white px-1.5 py-2 rounded-md mb-2"
@click="showFullClaim(veriClaim.id)" @click="showFullClaim(veriClaim.id)"
> >
Load Full Claim Details Load Full Claim Details
@@ -161,10 +163,12 @@
<pre>{{ util.inspect(fullClaim, false, null) }}</pre> <pre>{{ util.inspect(fullClaim, false, null) }}</pre>
</div> </div>
<a :href="apiServer + '/api/claim/' + veriClaim.id" target="_blank"> <a
<button class="bg-blue-600 text-white mt-4 px-4 py-2 rounded-md mb-4"> :href="apiServer + '/api/claim/' + veriClaim.id"
target="_blank"
class="block w-full text-center text-md uppercase bg-blue-600 text-white px-1.5 py-2 rounded-md mb-2"
>
View on the Public Server View on the Public Server
</button>
</a> </a>
</section> </section>
</template> </template>

View File

@@ -1,5 +1,6 @@
<template> <template>
<QuickNav selected="Discover"></QuickNav> <QuickNav selected="Discover"></QuickNav>
<TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
@@ -136,6 +137,7 @@ import { didInfo, ProjectData } from "@/libs/endorserServer";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue"; import InfiniteScroll from "@/components/InfiniteScroll.vue";
import EntityIcon from "@/components/EntityIcon.vue"; import EntityIcon from "@/components/EntityIcon.vue";
import TopMessage from "@/components/TopMessage.vue";
interface Notification { interface Notification {
group: string; group: string;
@@ -149,6 +151,7 @@ interface Notification {
QuickNav, QuickNav,
InfiniteScroll, InfiniteScroll,
EntityIcon, EntityIcon,
TopMessage,
}, },
}) })
export default class DiscoverView extends Vue { export default class DiscoverView extends Vue {

View File

@@ -1,5 +1,7 @@
<template> <template>
<QuickNav selected="Home"></QuickNav> <QuickNav selected="Home"></QuickNav>
<TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
@@ -146,6 +148,7 @@ import EntityIcon from "@/components/EntityIcon.vue";
import GiftedDialog from "@/components/GiftedDialog.vue"; import GiftedDialog from "@/components/GiftedDialog.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue"; import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
import { db, accountsDB } from "@/db/index"; import { db, accountsDB } from "@/db/index";
import { Account } from "@/db/tables/accounts"; import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
@@ -166,7 +169,13 @@ interface Notification {
} }
@Component({ @Component({
components: { GiftedDialog, QuickNav, EntityIcon, InfiniteScroll }, components: {
GiftedDialog,
QuickNav,
EntityIcon,
InfiniteScroll,
TopMessage,
},
}) })
export default class HomeView extends Vue { export default class HomeView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;

View File

@@ -1,5 +1,7 @@
<template> <template>
<QuickNav /> <QuickNav />
<TopMessage />
<!-- CONTENT --> <!-- CONTENT -->
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Breadcrumb --> <!-- Breadcrumb -->
@@ -282,6 +284,7 @@ import { Component, Vue } from "vue-facing-decorator";
import GiftedDialog from "@/components/GiftedDialog.vue"; import GiftedDialog from "@/components/GiftedDialog.vue";
import OfferDialog from "@/components/OfferDialog.vue"; import OfferDialog from "@/components/OfferDialog.vue";
import TopMessage from "@/components/TopMessage.vue";
import { accountsDB, db } from "@/db/index"; import { accountsDB, db } from "@/db/index";
import { Contact } from "@/db/tables/contacts"; import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
@@ -306,7 +309,7 @@ interface Notification {
} }
@Component({ @Component({
components: { EntityIcon, GiftedDialog, OfferDialog, QuickNav }, components: { EntityIcon, GiftedDialog, OfferDialog, QuickNav, TopMessage },
}) })
export default class ProjectViewView extends Vue { export default class ProjectViewView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;

View File

@@ -1,5 +1,7 @@
<template> <template>
<QuickNav selected="Projects"></QuickNav> <QuickNav selected="Projects"></QuickNav>
<TopMessage />
<section id="Content" class="p-6 pb-24"> <section id="Content" class="p-6 pb-24">
<!-- Heading --> <!-- Heading -->
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8"> <h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
@@ -79,6 +81,7 @@ import { IIdentifier } from "@veramo/core";
import InfiniteScroll from "@/components/InfiniteScroll.vue"; import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue"; import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue"; import EntityIcon from "@/components/EntityIcon.vue";
import TopMessage from "@/components/TopMessage.vue";
import { ProjectData } from "@/libs/endorserServer"; import { ProjectData } from "@/libs/endorserServer";
interface Notification { interface Notification {
@@ -89,7 +92,7 @@ interface Notification {
} }
@Component({ @Component({
components: { InfiniteScroll, QuickNav, EntityIcon }, components: { InfiniteScroll, QuickNav, EntityIcon, TopMessage },
}) })
export default class ProjectsView extends Vue { export default class ProjectsView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;