Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30552916a2 | |||
| 920d3f4d25 | |||
| d57aee203f | |||
| 7ababb4e1b | |||
| 41041d72c0 |
@@ -3,4 +3,4 @@ VITE_APP_SERVER=https://timesafari.app
|
|||||||
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H
|
VITE_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H
|
||||||
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
|
VITE_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch
|
||||||
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
|
VITE_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app
|
||||||
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.timesafari.app
|
VITE_DEFAULT_PARTNER_API_SERVER=https://partner-api.endorser.ch
|
||||||
|
|||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -6,10 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.53] - 2025.01.30
|
||||||
|
### Added
|
||||||
|
- Hints for contacting the creator of a project
|
||||||
|
|
||||||
|
|
||||||
|
## [0.3.52] - 2025.01.22
|
||||||
|
### Fixed
|
||||||
|
- User profile endpoint server for map was broken.
|
||||||
|
|
||||||
|
|
||||||
## [0.3.51] - 2025.01.22
|
## [0.3.51] - 2025.01.22
|
||||||
### Fixed
|
### Fixed
|
||||||
- User profile map jumped on first zoom.
|
- User profile map jumped on first zoom.
|
||||||
|
|
||||||
|
|
||||||
## [0.3.50] - 2025.01.20 - b9fedcd3fd3e34c3fb0fc79150d1a81a76eaeb40
|
## [0.3.50] - 2025.01.20 - b9fedcd3fd3e34c3fb0fc79150d1a81a76eaeb40
|
||||||
### Added
|
### Added
|
||||||
- User public profiles
|
- User public profiles
|
||||||
|
|||||||
@@ -70,11 +70,11 @@ TIME_SAFARI_APP_TITLE="TimeSafari_Test" VITE_APP_SERVER=https://test.timesafari.
|
|||||||
|
|
||||||
* `pkgx +npm sh`
|
* `pkgx +npm sh`
|
||||||
|
|
||||||
* `cd crowd-funder-for-time-pwa && git pull && git checkout 0.3.36 && npm install && npm run build && cd -`
|
* `cd crowd-funder-for-time-pwa && git checkout master && git pull && git checkout 0.3.36 && npm install && npm run build && cd -`
|
||||||
|
|
||||||
(The plain `npm run build` will use the .env.production file.)
|
(The plain `npm run build` uses the .env.production file.)
|
||||||
|
|
||||||
* Back up the time-safari/dist folder, then `mv time-safari/dist time-safari-dist-prev9` && `mv crowd-funder-for-time-pwa/dist time-safari/`
|
* Back up the time-safari/dist folder, then `mv time-safari/dist time-safari-dist-prev.0` && `mv crowd-funder-for-time-pwa/dist time-safari/`
|
||||||
|
|
||||||
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production.
|
* Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production.
|
||||||
|
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.51",
|
"version": "0.3.53",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.51",
|
"version": "0.3.53",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^6.1.2",
|
"@capacitor/android": "^6.1.2",
|
||||||
"@capacitor/cli": "^6.1.2",
|
"@capacitor/cli": "^6.1.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "TimeSafari",
|
"name": "TimeSafari",
|
||||||
"version": "0.3.51",
|
"version": "0.3.53",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"serve": "vite preview",
|
"serve": "vite preview",
|
||||||
|
|||||||
182
src/components/HiddenDidDialog.vue
Normal file
182
src/components/HiddenDidDialog.vue
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="isOpen"
|
||||||
|
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
|
||||||
|
>
|
||||||
|
<div class="bg-white rounded-lg p-6 max-w-2xl w-full mx-4">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="text-xl font-bold capitalize">{{ roleName }} Details</h2>
|
||||||
|
<button @click="close" class="text-gray-500 hover:text-gray-700">
|
||||||
|
<fa icon="times" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content -->
|
||||||
|
<!-- This is somewhat similar to ClaimView.vue and ConfirmGiftView.vue -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<p class="mb-4">
|
||||||
|
<span v-if="R.isEmpty(visibleToDids)">
|
||||||
|
The {{ roleName }} is not visible to you or any of your contacts.
|
||||||
|
</span>
|
||||||
|
<span v-else> The {{ roleName }} is not visible to you. </span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div v-if="R.isEmpty(visibleToDids)">
|
||||||
|
<p class="mt-2">
|
||||||
|
You can ask one of your contacts to take a look and see if their
|
||||||
|
contacts can see more details. Someone is connected to people closer
|
||||||
|
to them; if you don't know who to ask, try the person who registered
|
||||||
|
you.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<p class="mb-2">
|
||||||
|
They are visible to some of your contacts. If you'd like an
|
||||||
|
introduction, ask them if they'll tell you more.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="ml-4">
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="(visDid, idx) of visibleToDids"
|
||||||
|
:key="idx"
|
||||||
|
class="list-disc ml-4 mb-2"
|
||||||
|
>
|
||||||
|
<div class="text-sm">
|
||||||
|
<span>
|
||||||
|
{{ didInfo(visDid) }}
|
||||||
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
||||||
|
<a
|
||||||
|
:href="`/did/${visDid}`"
|
||||||
|
target="_blank"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<span v-if="canShare">
|
||||||
|
If you'd like an introduction,
|
||||||
|
<a @click="onClickShareClaim()" class="text-blue-500"
|
||||||
|
>click here to share the information with them and ask if they'll
|
||||||
|
tell you more about the {{ roleName }}.</a
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
If you'd like an introduction,
|
||||||
|
<a
|
||||||
|
@click="copyToClipboard('A link to this page', windowLocation)"
|
||||||
|
class="text-blue-500"
|
||||||
|
>click here to copy this page, paste it into a message, and ask if
|
||||||
|
they'll tell you more about the {{ roleName }}.</a
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<button
|
||||||
|
@click="close"
|
||||||
|
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
|
import * as R from "ramda";
|
||||||
|
import { useClipboard } from "@vueuse/core";
|
||||||
|
import { Contact } from "@/db/tables/contacts";
|
||||||
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
|
import { NotificationIface } from "@/constants/app";
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class HiddenDidDialog extends Vue {
|
||||||
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||||
|
|
||||||
|
isOpen = false;
|
||||||
|
roleName = "";
|
||||||
|
visibleToDids: string[] = [];
|
||||||
|
allContacts: Array<Contact> = [];
|
||||||
|
activeDid = "";
|
||||||
|
allMyDids: Array<string> = [];
|
||||||
|
canShare = false;
|
||||||
|
windowLocation = window.location.href;
|
||||||
|
|
||||||
|
R = R;
|
||||||
|
serverUtil = serverUtil;
|
||||||
|
|
||||||
|
created() {
|
||||||
|
// When Chrome compatibility is fixed https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API#api.navigator.canshare
|
||||||
|
// then use this truer check: navigator.canShare && navigator.canShare()
|
||||||
|
this.canShare = !!navigator.share;
|
||||||
|
}
|
||||||
|
|
||||||
|
open(
|
||||||
|
roleName: string,
|
||||||
|
visibleToDids: string[],
|
||||||
|
allContacts: Array<Contact>,
|
||||||
|
activeDid: string,
|
||||||
|
allMyDids: Array<string>,
|
||||||
|
) {
|
||||||
|
this.roleName = roleName;
|
||||||
|
this.visibleToDids = visibleToDids;
|
||||||
|
this.allContacts = allContacts;
|
||||||
|
this.activeDid = activeDid;
|
||||||
|
this.allMyDids = allMyDids;
|
||||||
|
this.isOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.isOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
didInfo(did: string) {
|
||||||
|
return serverUtil.didInfo(
|
||||||
|
did,
|
||||||
|
this.activeDid,
|
||||||
|
this.allMyDids,
|
||||||
|
this.allContacts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
copyToClipboard(name: string, text: string) {
|
||||||
|
useClipboard()
|
||||||
|
.copy(text)
|
||||||
|
.then(() => {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "toast",
|
||||||
|
title: "Copied",
|
||||||
|
text: (name || "That") + " was copied to the clipboard.",
|
||||||
|
},
|
||||||
|
2000,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickShareClaim() {
|
||||||
|
this.copyToClipboard("A link to this page", this.windowLocation);
|
||||||
|
window.navigator.share({
|
||||||
|
title: "Help Connect Me",
|
||||||
|
text: "I'm trying to find the people who recorded this. Can you help me?",
|
||||||
|
url: this.windowLocation,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<h1 class="text-xl font-bold text-center mb-4 relative">
|
<h1 class="text-xl font-bold text-center mb-4 relative">
|
||||||
Welcome to Time Safari
|
Welcome to Time Safari
|
||||||
<br />
|
<br />
|
||||||
- Showcasing Gratitude & Magnifing Time
|
- Showcasing Gratitude & Magnifying Time
|
||||||
<div
|
<div
|
||||||
class="text-lg text-center leading-none absolute right-0 -top-1"
|
class="text-lg text-center leading-none absolute right-0 -top-1"
|
||||||
@click="onClickClose(true)"
|
@click="onClickClose(true)"
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ export function didInfoForContact(
|
|||||||
} else if (contact) {
|
} else if (contact) {
|
||||||
return {
|
return {
|
||||||
displayName: contact.name || "Contact With No Name",
|
displayName: contact.name || "Contact With No Name",
|
||||||
known: !!contact,
|
known: true,
|
||||||
profileImageUrl: contact.profileImageUrl,
|
profileImageUrl: contact.profileImageUrl,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@@ -478,6 +478,19 @@ export function didInfoForContact(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns full contact info object (never undefined), where did is searched in contacts and allMyDids
|
||||||
|
*/
|
||||||
|
export function didInfoObject(
|
||||||
|
did: string | undefined,
|
||||||
|
activeDid: string | undefined,
|
||||||
|
allMyDids: string[],
|
||||||
|
contacts: Contact[],
|
||||||
|
): { known: boolean; displayName: string; profileImageUrl?: string } {
|
||||||
|
const contact = contactForDid(did, contacts);
|
||||||
|
return didInfoForContact(did, activeDid, contact, allMyDids);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
always returns text, maybe something like "unnamed" or "unknown"
|
always returns text, maybe something like "unnamed" or "unknown"
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export default class ClaimCertificateView extends Vue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (claimData.claimType === "GiveAction" && claimData.claim.agent) {
|
if (claimData.claimType === "GiveAction" && claimData.claim.agent) {
|
||||||
const presentedText = "Thanks To ";
|
const presentedText = "Thanks To";
|
||||||
ctx.font = "14px Arial";
|
ctx.font = "14px Arial";
|
||||||
const presentedWidth = ctx.measureText(presentedText).width;
|
const presentedWidth = ctx.measureText(presentedText).width;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
@@ -148,8 +148,36 @@ export default class ClaimCertificateView extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alternatively, show some offer details
|
||||||
|
if (claimData.claimType === "Offer") {
|
||||||
|
const presentedText = "To";
|
||||||
|
ctx.font = "14px Arial";
|
||||||
|
const presentedWidth = ctx.measureText(presentedText).width;
|
||||||
|
ctx.fillText(
|
||||||
|
presentedText,
|
||||||
|
(CANVAS_WIDTH - presentedWidth) / 2, // Center horizontally
|
||||||
|
CANVAS_HEIGHT * 0.37,
|
||||||
|
);
|
||||||
|
// fulfills
|
||||||
|
const agentDid =
|
||||||
|
claimData.claim.agent.identifier || claimData.claim.agent;
|
||||||
|
const agentText = serverUtil.didInfoForCertificate(
|
||||||
|
agentDid,
|
||||||
|
allContacts,
|
||||||
|
);
|
||||||
|
ctx.font = "bold 20px Arial";
|
||||||
|
const agentWidth = ctx.measureText(agentText).width;
|
||||||
|
ctx.fillText(
|
||||||
|
agentText,
|
||||||
|
(CANVAS_WIDTH - agentWidth) / 2, // Center horizontally
|
||||||
|
CANVAS_HEIGHT * 0.41,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const descriptionText =
|
const descriptionText =
|
||||||
claimData.claim.name || claimData.claim.description;
|
claimData.claim.name ||
|
||||||
|
claimData.claim.description ||
|
||||||
|
claimData.claim.itemOffered?.description; // for Offers
|
||||||
if (descriptionText) {
|
if (descriptionText) {
|
||||||
const descriptionLine =
|
const descriptionLine =
|
||||||
descriptionText.length > 50
|
descriptionText.length > 50
|
||||||
@@ -164,12 +192,12 @@ export default class ClaimCertificateView extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
const possibleObject =
|
||||||
claimData.claim.object?.amountOfThisGood &&
|
claimData.claim.object || // for GiveActions
|
||||||
claimData.claim.object?.unitCode
|
claimData.claim.includesObject; // for Offers
|
||||||
) {
|
if (possibleObject?.amountOfThisGood && possibleObject?.unitCode) {
|
||||||
const amount = claimData.claim.object.amountOfThisGood;
|
const amount = possibleObject.amountOfThisGood;
|
||||||
const unit = claimData.claim.object.unitCode;
|
const unit = possibleObject.unitCode;
|
||||||
const amountText = serverUtil.displayAmount(unit, amount);
|
const amountText = serverUtil.displayAmount(unit, amount);
|
||||||
const amountWidth = ctx.measureText(amountText).width;
|
const amountWidth = ctx.measureText(amountText).width;
|
||||||
// if there was no description then put this in that spot, otherwise put it below the description
|
// if there was no description then put this in that spot, otherwise put it below the description
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<button
|
<button
|
||||||
title="Copy Link"
|
title="Copy Link"
|
||||||
@click="
|
@click="
|
||||||
copyToClipboard('Current page link', window.location.href)
|
copyToClipboard('A link to this page', window.location.href)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<fa icon="link" class="text-slate-500" />
|
<fa icon="link" class="text-slate-500" />
|
||||||
@@ -270,16 +270,13 @@
|
|||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ didInfo(confirmerId) }}
|
{{ didInfo(confirmerId) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
|
||||||
<button
|
<a
|
||||||
@click="
|
:href="`/did/${confirmerId}`"
|
||||||
copyToClipboard(
|
target="_blank"
|
||||||
'The DID of ' + confirmerId,
|
class="text-blue-500"
|
||||||
confirmerId,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
</button>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -311,16 +308,13 @@
|
|||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ didInfo(confsVisibleTo) }}
|
{{ didInfo(confsVisibleTo) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(confsVisibleTo)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(confsVisibleTo)">
|
||||||
<button
|
<a
|
||||||
@click="
|
:href="`/did/${confsVisibleTo}`"
|
||||||
copyToClipboard(
|
target="_blank"
|
||||||
'The DID of ' + confsVisibleTo,
|
class="text-blue-500"
|
||||||
confsVisibleTo,
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
</button>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -344,7 +338,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Note that a similar section is found in ConfirmGiftView.vue -->
|
<!-- Note that a similar section is found in ConfirmGiftView.vue, and kinda in HiddenDidDialog.vue -->
|
||||||
<h2
|
<h2
|
||||||
class="font-bold uppercase text-xl text-blue-500 mt-8 cursor-pointer"
|
class="font-bold uppercase text-xl text-blue-500 mt-8 cursor-pointer"
|
||||||
@click="showVeriClaimDump = !showVeriClaimDump"
|
@click="showVeriClaimDump = !showVeriClaimDump"
|
||||||
@@ -364,24 +358,26 @@
|
|||||||
Some of the details are not visible to you; they show as "HIDDEN". They
|
Some of the details are not visible to you; they show as "HIDDEN". They
|
||||||
are not visible to any of your direct contacts, either.
|
are not visible to any of your direct contacts, either.
|
||||||
<span v-if="canShare">
|
<span v-if="canShare">
|
||||||
If you'd like to ask any of your contacts to take a look and see if
|
You can ask one of your contacts to take a look and see if their
|
||||||
their contacts can see more details,
|
contacts can see more details:
|
||||||
<a @click="onClickShareClaim()" class="text-blue-500"
|
<a @click="onClickShareClaim()" class="text-blue-500"
|
||||||
>click to send them this info</a
|
>click to send them this page info</a
|
||||||
>
|
>
|
||||||
and see if they are willing to make an introduction. They are surely
|
and see if they can make an introduction. Someone is connected to
|
||||||
connected to someone; if you don't know who to ask, you might try the
|
people closer to them; if you don't know who to ask, try the person
|
||||||
person who registered you.
|
who registered you.
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
If you'd like to ask any of your contacts to take a look and see if
|
You can ask one of your contacts to take a look and see if their
|
||||||
their contacts can see more details,
|
contacts can see more details:
|
||||||
<a
|
<a
|
||||||
@click="copyToClipboard('A link to this page', windowLocation)"
|
@click="copyToClipboard('A link to this page', windowLocation)"
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>share this page with them</a
|
>click to copy this page info</a
|
||||||
>
|
>
|
||||||
and see if they are willing to make an introduction.
|
and see if they can make an introduction. Someone is connected to
|
||||||
|
people closer to them; if you don't know who to ask, try the person
|
||||||
|
who registered you.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -425,18 +421,21 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ didInfo(visDid) }}
|
{{ didInfo(visDid) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
||||||
<button
|
<a
|
||||||
@click="copyToClipboard('The DID of ' + visDid, visDid)"
|
:href="`/did/${visDid}`"
|
||||||
|
target="_blank"
|
||||||
|
class="text-blue-500"
|
||||||
>
|
>
|
||||||
<fa icon="copy" class="text-slate-400 fa-fw" />
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
</button>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="veriClaim.publicUrls?.[visDid]"
|
<span v-if="veriClaim.publicUrls?.[visDid]"
|
||||||
>, found at <a
|
>, found at <a
|
||||||
:href="veriClaim.publicUrls?.[visDid]"
|
:href="veriClaim.publicUrls?.[visDid]"
|
||||||
|
target="_blank"
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>
|
>
|
||||||
<fa icon="globe" class="fa-fw text-slate-400" />
|
<fa icon="globe" class="fa-fw" />
|
||||||
{{
|
{{
|
||||||
veriClaim.publicUrls[visDid].substring(
|
veriClaim.publicUrls[visDid].substring(
|
||||||
veriClaim.publicUrls[visDid].indexOf("//") + 2,
|
veriClaim.publicUrls[visDid].indexOf("//") + 2,
|
||||||
@@ -452,7 +451,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="isEditedGlobalId" class="mt-2">
|
<span v-if="isEditedGlobalId" class="mt-2">
|
||||||
This record is an edited version. The latest version is here.
|
This record is an edited version. The latest version is shown.
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
<!-- Keep the dump contents directly between > and < to avoid weird spacing. -->
|
<!-- Keep the dump contents directly between > and < to avoid weird spacing. -->
|
||||||
@@ -963,9 +962,10 @@ export default class ClaimView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClickShareClaim() {
|
onClickShareClaim() {
|
||||||
|
this.copyToClipboard("A link to this page", this.windowLocation);
|
||||||
window.navigator.share({
|
window.navigator.share({
|
||||||
title: "Help Connect Me",
|
title: "Help Connect Me",
|
||||||
text: "I'm trying to find the full details of this claim. Can you help me?",
|
text: "I'm trying to find the people who recorded this. Can you help me?",
|
||||||
url: this.windowLocation,
|
url: this.windowLocation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,7 +254,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Note that a similar section is found in ClaimView.vue -->
|
<!-- Note that a similar section is found in ClaimView.vue, and kinda in HiddenDidDialog.vue -->
|
||||||
<h2
|
<h2
|
||||||
class="font-bold uppercase text-xl text-blue-500 mt-8 cursor-pointer"
|
class="font-bold uppercase text-xl text-blue-500 mt-8 cursor-pointer"
|
||||||
@click="showVeriClaimDump = !showVeriClaimDump"
|
@click="showVeriClaimDump = !showVeriClaimDump"
|
||||||
@@ -274,24 +274,26 @@
|
|||||||
Some of the details are not visible to you; they show as "HIDDEN".
|
Some of the details are not visible to you; they show as "HIDDEN".
|
||||||
They are not visible to any of your direct contacts, either.
|
They are not visible to any of your direct contacts, either.
|
||||||
<span v-if="canShare">
|
<span v-if="canShare">
|
||||||
If you'd like to ask any of your contacts to take a look and see if
|
You can ask one of your contacts to take a look and see if their
|
||||||
their contacts can see more details,
|
contacts can see more details:
|
||||||
<a @click="onClickShareClaim()" class="text-blue-500"
|
<a @click="onClickShareClaim()" class="text-blue-500"
|
||||||
>click to send them this info</a
|
>click to send them this page info</a
|
||||||
>
|
>
|
||||||
and see if they are willing to make an introduction. They are surely
|
and see if they can make an introduction. Someone is connected to
|
||||||
connected to someone; if you don't know who to ask, you might try
|
people closer to them; if you don't know who to ask, try the person
|
||||||
the person who registered you.
|
who registered you.
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
If you'd like to ask any of your contacts to take a look and see if
|
You can ask one of your contacts to take a look and see if their
|
||||||
their contacts can see more details,
|
contacts can see more details:
|
||||||
<a
|
<a
|
||||||
@click="copyToClipboard('Location', windowLocation.href)"
|
@click="copyToClipboard('A link to this page', windowLocation)"
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>share this page with them</a
|
>click to copy this page info</a
|
||||||
>
|
>
|
||||||
and see if they are willing to make an introduction.
|
and see if they can make an introduction. Someone is connected to
|
||||||
|
people closer to them; if you don't know who to ask, try the person
|
||||||
|
who registered you.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -308,9 +310,7 @@
|
|||||||
<span v-else>
|
<span v-else>
|
||||||
If you'd like an introduction,
|
If you'd like an introduction,
|
||||||
<a
|
<a
|
||||||
@click="
|
@click="copyToClipboard('A link to this page', windowLocation)"
|
||||||
copyToClipboard('A link to this page', windowLocation.href)
|
|
||||||
"
|
|
||||||
class="text-blue-500"
|
class="text-blue-500"
|
||||||
>share this page with them and ask if they'll tell you more about
|
>share this page with them and ask if they'll tell you more about
|
||||||
about the participants.</a
|
about the participants.</a
|
||||||
@@ -448,7 +448,7 @@ export default class ClaimView extends Vue {
|
|||||||
veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD;
|
||||||
veriClaimDump = "";
|
veriClaimDump = "";
|
||||||
veriClaimDidsVisible = {};
|
veriClaimDidsVisible = {};
|
||||||
windowLocation = window.location;
|
windowLocation = window.location.href;
|
||||||
|
|
||||||
R = R;
|
R = R;
|
||||||
yaml = yaml;
|
yaml = yaml;
|
||||||
@@ -856,10 +856,11 @@ export default class ClaimView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClickShareClaim() {
|
onClickShareClaim() {
|
||||||
|
this.copyToClipboard("A link to this page", this.windowLocation);
|
||||||
window.navigator.share({
|
window.navigator.share({
|
||||||
title: "Help Connect Me",
|
title: "Help Connect Me",
|
||||||
text: "I'm trying to find the full details of this claim. Can you help me?",
|
text: "I'm trying to find the full details of this claim. Can you help me?",
|
||||||
url: this.windowLocation.href,
|
url: this.windowLocation,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<fa
|
<fa
|
||||||
v-if="dids[0] == selectedArrayFirstDid"
|
v-if="dids[0] == selectedArrayFirstDid"
|
||||||
icon="circle"
|
icon="circle"
|
||||||
class="fa-fw text-blue-400 text-xl mr-3"
|
class="fa-fw text-blue-500 text-xl mr-3"
|
||||||
></fa>
|
></fa>
|
||||||
<fa
|
<fa
|
||||||
v-else
|
v-else
|
||||||
|
|||||||
@@ -203,8 +203,12 @@ import "leaflet/dist/leaflet.css";
|
|||||||
import { AxiosError, AxiosRequestHeaders } from "axios";
|
import { AxiosError, AxiosRequestHeaders } from "axios";
|
||||||
import { DateTime } from "luxon";
|
import { DateTime } from "luxon";
|
||||||
import { hexToBytes } from "@noble/hashes/utils";
|
import { hexToBytes } from "@noble/hashes/utils";
|
||||||
import type { EventTemplate, VerifiedEvent } from "nostr-tools/lib/types/core";
|
// these core imports could also be included as "import type ..."
|
||||||
import { accountFromSeedWords } from "nostr-tools/nip06";
|
import { EventTemplate, UnsignedEvent, VerifiedEvent } from "nostr-tools/core";
|
||||||
|
import {
|
||||||
|
accountFromExtendedKey,
|
||||||
|
extendedKeysFromSeedWords,
|
||||||
|
} from "nostr-tools/nip06";
|
||||||
import { finalizeEvent, serializeEvent } from "nostr-tools/pure";
|
import { finalizeEvent, serializeEvent } from "nostr-tools/pure";
|
||||||
import { Component, Vue } from "vue-facing-decorator";
|
import { Component, Vue } from "vue-facing-decorator";
|
||||||
import { LMap, LMarker, LTileLayer } from "@vue-leaflet/vue-leaflet";
|
import { LMap, LMarker, LTileLayer } from "@vue-leaflet/vue-leaflet";
|
||||||
@@ -225,7 +229,6 @@ import {
|
|||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import {
|
import {
|
||||||
retrieveAccountCount,
|
retrieveAccountCount,
|
||||||
retrieveAccountMetadata,
|
|
||||||
retrieveFullyDecryptedAccount,
|
retrieveFullyDecryptedAccount,
|
||||||
} from "@/libs/util";
|
} from "@/libs/util";
|
||||||
|
|
||||||
@@ -472,31 +475,45 @@ export default class NewEditProjectView extends Vue {
|
|||||||
try {
|
try {
|
||||||
const resp = await this.axios.post(url, payload, { headers });
|
const resp = await this.axios.post(url, payload, { headers });
|
||||||
if (resp.data?.success?.handleId) {
|
if (resp.data?.success?.handleId) {
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "success",
|
||||||
|
title: "Saved",
|
||||||
|
text: "The project was saved successfully.",
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
|
||||||
this.errorMessage = "";
|
this.errorMessage = "";
|
||||||
|
|
||||||
const projectPath = encodeURIComponent(resp.data.success.handleId);
|
const projectPath = encodeURIComponent(resp.data.success.handleId);
|
||||||
|
|
||||||
if (this.sendToTrustroots || this.sendToTripHopping) {
|
if (this.sendToTrustroots || this.sendToTripHopping) {
|
||||||
if (this.latitude && this.longitude) {
|
if (this.latitude && this.longitude) {
|
||||||
let signedPayload: VerifiedEvent | undefined; // sign something to prove ownership of pubkey
|
let payloadAndKey; // sign something to prove ownership of pubkey
|
||||||
if (this.sendToTrustroots) {
|
if (this.sendToTrustroots) {
|
||||||
signedPayload = await this.signPayload();
|
payloadAndKey = await this.signSomePayload();
|
||||||
|
// not going to await... the save was successful, so we'll continue to the next page
|
||||||
this.sendToNostrPartner(
|
this.sendToNostrPartner(
|
||||||
"NOSTR-EVENT-TRUSTROOTS",
|
"NOSTR-EVENT-TRUSTROOTS",
|
||||||
"Trustroots",
|
"Trustroots",
|
||||||
resp.data.success.claimId,
|
resp.data.success.claimId,
|
||||||
signedPayload,
|
payloadAndKey.signedEvent,
|
||||||
|
payloadAndKey.publicExtendedKey,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.sendToTripHopping) {
|
if (this.sendToTripHopping) {
|
||||||
if (!signedPayload) {
|
if (!payloadAndKey) {
|
||||||
signedPayload = await this.signPayload();
|
payloadAndKey = await this.signSomePayload();
|
||||||
}
|
}
|
||||||
|
// not going to await... the save was successful, so we'll continue to the next page
|
||||||
this.sendToNostrPartner(
|
this.sendToNostrPartner(
|
||||||
"NOSTR-EVENT-TRIPHOPPING",
|
"NOSTR-EVENT-TRIPHOPPING",
|
||||||
"TripHopping",
|
"TripHopping",
|
||||||
resp.data.success.claimId,
|
resp.data.success.claimId,
|
||||||
signedPayload,
|
payloadAndKey.signedEvent,
|
||||||
|
payloadAndKey.publicExtendedKey,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -576,19 +593,28 @@ export default class NewEditProjectView extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async signPayload(): Promise<VerifiedEvent> {
|
/**
|
||||||
|
* @return a signed payload and an extended public key for later transmission
|
||||||
|
*/
|
||||||
|
private async signSomePayload(): Promise<{
|
||||||
|
signedEvent: VerifiedEvent;
|
||||||
|
publicExtendedKey: string;
|
||||||
|
}> {
|
||||||
const account = await retrieveFullyDecryptedAccount(this.activeDid);
|
const account = await retrieveFullyDecryptedAccount(this.activeDid);
|
||||||
// get the last number of the derivationPath
|
// get the last number of the derivationPath
|
||||||
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
||||||
// remove any trailing '
|
// remove any trailing '
|
||||||
const finalDerNumNoApostrophe = finalDerNum?.replace(/'/g, "");
|
const finalDerNumNoApostrophe = finalDerNum?.replace(/'/g, "");
|
||||||
const accountNum = Number(finalDerNumNoApostrophe || 0);
|
const accountNum = Number(finalDerNumNoApostrophe || 0);
|
||||||
const pubPri = accountFromSeedWords(
|
const extPubPri = extendedKeysFromSeedWords(
|
||||||
account?.mnemonic as string,
|
account?.mnemonic as string,
|
||||||
"",
|
"",
|
||||||
accountNum,
|
accountNum,
|
||||||
);
|
);
|
||||||
const privateBytes = hexToBytes(pubPri?.privateKey);
|
const publicExtendedKey: string = extPubPri?.publicExtendedKey;
|
||||||
|
const privateExtendedKey = extPubPri?.privateExtendedKey;
|
||||||
|
const privateKey = accountFromExtendedKey(privateExtendedKey).privateKey;
|
||||||
|
const privateBytes = hexToBytes(privateKey);
|
||||||
// No real content is necessary, we just want something signed,
|
// No real content is necessary, we just want something signed,
|
||||||
// so we might as well use nostr libs for nostr functions.
|
// so we might as well use nostr libs for nostr functions.
|
||||||
// Besides: someday we may create real content that we can relay.
|
// Besides: someday we may create real content that we can relay.
|
||||||
@@ -598,9 +624,12 @@ export default class NewEditProjectView extends Vue {
|
|||||||
content: "",
|
content: "",
|
||||||
created_at: 0,
|
created_at: 0,
|
||||||
};
|
};
|
||||||
// Why does IntelliJ not see matching types?
|
const signedEvent: VerifiedEvent = finalizeEvent(
|
||||||
const signedEvent = finalizeEvent(event, privateBytes);
|
// Why does IntelliJ not see matching types?
|
||||||
return signedEvent;
|
event as EventTemplate,
|
||||||
|
privateBytes,
|
||||||
|
) as VerifiedEvent;
|
||||||
|
return { signedEvent, publicExtendedKey };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendToNostrPartner(
|
private async sendToNostrPartner(
|
||||||
@@ -608,41 +637,37 @@ export default class NewEditProjectView extends Vue {
|
|||||||
serviceName: string,
|
serviceName: string,
|
||||||
jwtId: string,
|
jwtId: string,
|
||||||
signedPayload: VerifiedEvent,
|
signedPayload: VerifiedEvent,
|
||||||
|
publicExtendedKey: string,
|
||||||
) {
|
) {
|
||||||
// first, get the public key for nostr
|
|
||||||
const account = await retrieveAccountMetadata(this.activeDid);
|
|
||||||
// get the last number of the derivationPath
|
|
||||||
const finalDerNum = account?.derivationPath?.split?.("/")?.reverse()[0];
|
|
||||||
// remove any trailing '
|
|
||||||
const finalDerNumNoApostrophe = finalDerNum?.replace(/'/g, "");
|
|
||||||
const accountNum = Number(finalDerNumNoApostrophe || 0);
|
|
||||||
const pubPri = accountFromSeedWords(
|
|
||||||
account?.mnemonic as string,
|
|
||||||
"",
|
|
||||||
accountNum,
|
|
||||||
);
|
|
||||||
const nostrPubKey = pubPri?.publicKey;
|
|
||||||
|
|
||||||
let partnerServer = DEFAULT_PARTNER_API_SERVER;
|
|
||||||
const settings = await retrieveSettingsForActiveAccount();
|
|
||||||
if (settings.partnerApiServer) {
|
|
||||||
partnerServer = settings.partnerApiServer;
|
|
||||||
}
|
|
||||||
const endorserPartnerUrl = partnerServer + "/api/partner/link";
|
|
||||||
const timeSafariUrl = window.location.origin + "/claim/" + jwtId;
|
|
||||||
const content = this.fullClaim.name + " - see " + timeSafariUrl;
|
|
||||||
// Why does IntelliJ not see matching types?
|
|
||||||
const payload = serializeEvent(signedPayload);
|
|
||||||
const partnerParams = {
|
|
||||||
jwtId: jwtId,
|
|
||||||
linkCode: linkCode,
|
|
||||||
inputJson: JSON.stringify(content),
|
|
||||||
pubKeyHex: nostrPubKey,
|
|
||||||
pubKeyImage: payload,
|
|
||||||
pubKeySigHex: signedPayload.sig,
|
|
||||||
};
|
|
||||||
const headers = await getHeaders(this.activeDid);
|
|
||||||
try {
|
try {
|
||||||
|
let partnerServer = DEFAULT_PARTNER_API_SERVER;
|
||||||
|
const settings = await retrieveSettingsForActiveAccount();
|
||||||
|
if (settings.partnerApiServer) {
|
||||||
|
partnerServer = settings.partnerApiServer;
|
||||||
|
}
|
||||||
|
const endorserPartnerUrl = partnerServer + "/api/partner/link";
|
||||||
|
const timeSafariUrl = window.location.origin + "/claim/" + jwtId;
|
||||||
|
const content = this.fullClaim.name + " - see " + timeSafariUrl;
|
||||||
|
const publicKeyHex = accountFromExtendedKey(publicExtendedKey).publicKey;
|
||||||
|
const unsignedPayload: UnsignedEvent = {
|
||||||
|
// why doesn't "...signedPayload" work?
|
||||||
|
kind: signedPayload.kind,
|
||||||
|
tags: signedPayload.tags,
|
||||||
|
content: signedPayload.content,
|
||||||
|
created_at: signedPayload.created_at,
|
||||||
|
pubkey: publicKeyHex,
|
||||||
|
};
|
||||||
|
// Why does IntelliJ not see matching types?
|
||||||
|
const payload = serializeEvent(unsignedPayload as UnsignedEvent);
|
||||||
|
const partnerParams = {
|
||||||
|
jwtId: jwtId,
|
||||||
|
linkCode: linkCode,
|
||||||
|
inputJson: JSON.stringify(content),
|
||||||
|
pubKeyHex: publicKeyHex,
|
||||||
|
pubKeyImage: payload,
|
||||||
|
pubKeySigHex: signedPayload.sig,
|
||||||
|
};
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
const linkResp = await this.axios.post(
|
const linkResp = await this.axios.post(
|
||||||
endorserPartnerUrl,
|
endorserPartnerUrl,
|
||||||
partnerParams,
|
partnerParams,
|
||||||
@@ -731,7 +756,7 @@ export default class NewEditProjectView extends Vue {
|
|||||||
group: "alert",
|
group: "alert",
|
||||||
type: "info",
|
type: "info",
|
||||||
title: "About Nostr Events",
|
title: "About Nostr Events",
|
||||||
text: "This will cause a submission to a partner on the nostr network. It will contain your public key data which may allow correlation, so don't allow this if you're not comfortable with that.",
|
text: "This will submit this project to a partner on the nostr network. It will contain your public key data which may allow correlation, so don't allow this if you're not comfortable with that.",
|
||||||
},
|
},
|
||||||
7000,
|
7000,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -49,22 +49,22 @@
|
|||||||
<div class="text-sm mb-3">
|
<div class="text-sm mb-3">
|
||||||
<div class="truncate">
|
<div class="truncate">
|
||||||
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
<fa icon="user" class="fa-fw text-slate-400"></fa>
|
||||||
{{
|
{{ issuerInfoObject?.displayName }}
|
||||||
serverUtil.didInfo(issuer, activeDid, allMyDids, allContacts)
|
|
||||||
}}
|
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(issuer)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(issuer)">
|
||||||
<button
|
<a
|
||||||
@click="
|
:href="`/did/${issuer}`"
|
||||||
libsUtil.doCopyTwoSecRedo(
|
target="_blank"
|
||||||
issuer,
|
class="text-blue-500"
|
||||||
() => (showDidCopy = !showDidCopy),
|
|
||||||
)
|
|
||||||
"
|
|
||||||
class="ml-2 mr-2"
|
|
||||||
>
|
>
|
||||||
<fa icon="copy" class="text-slate-400 fa-fw"></fa>
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
</button>
|
</a>
|
||||||
<span v-show="showDidCopy">Copied DID</span>
|
</span>
|
||||||
|
<span v-else-if="serverUtil.isHiddenDid(issuer)">
|
||||||
|
<fa
|
||||||
|
icon="info-circle"
|
||||||
|
class="fa-fw text-blue-500 cursor-pointer"
|
||||||
|
@click="openHiddenDidDialog()"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="startTime">
|
<div v-if="startTime">
|
||||||
@@ -76,14 +76,21 @@
|
|||||||
<a
|
<a
|
||||||
:href="getOpenStreetMapUrl()"
|
:href="getOpenStreetMapUrl()"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="underline"
|
class="underline text-blue-500"
|
||||||
>Map View
|
>Map View
|
||||||
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
<fa
|
||||||
|
icon="arrow-up-right-from-square"
|
||||||
|
class="fa-fw text-blue-500"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="url">
|
<div v-if="url">
|
||||||
<fa icon="globe" class="fa-fw text-slate-400"></fa>
|
<fa icon="globe" class="fa-fw text-slate-400"></fa>
|
||||||
<a :href="addScheme(url)" target="_blank" class="underline">
|
<a
|
||||||
|
:href="addScheme(url)"
|
||||||
|
target="_blank"
|
||||||
|
class="underline text-blue-500"
|
||||||
|
>
|
||||||
{{ domainForWebsite(this.url) }}
|
{{ domainForWebsite(this.url) }}
|
||||||
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
<fa icon="arrow-up-right-from-square" class="fa-fw" />
|
||||||
</a>
|
</a>
|
||||||
@@ -477,6 +484,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<HiddenDidDialog ref="hiddenDidDialog" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -508,11 +517,13 @@ import {
|
|||||||
} from "@/libs/endorserServer";
|
} from "@/libs/endorserServer";
|
||||||
import * as serverUtil from "@/libs/endorserServer";
|
import * as serverUtil from "@/libs/endorserServer";
|
||||||
import { retrieveAccountDids } from "@/libs/util";
|
import { retrieveAccountDids } from "@/libs/util";
|
||||||
|
import HiddenDidDialog from "@/components/HiddenDidDialog.vue";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
EntityIcon,
|
EntityIcon,
|
||||||
GiftedDialog,
|
GiftedDialog,
|
||||||
|
HiddenDidDialog,
|
||||||
OfferDialog,
|
OfferDialog,
|
||||||
ProjectIcon,
|
ProjectIcon,
|
||||||
QuickNav,
|
QuickNav,
|
||||||
@@ -524,6 +535,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
|
|
||||||
activeDid = "";
|
activeDid = "";
|
||||||
agentDid = "";
|
agentDid = "";
|
||||||
|
agentDidVisibleToDids: Array<string> = [];
|
||||||
allMyDids: Array<string> = [];
|
allMyDids: Array<string> = [];
|
||||||
allContacts: Array<Contact> = [];
|
allContacts: Array<Contact> = [];
|
||||||
apiServer = "";
|
apiServer = "";
|
||||||
@@ -540,6 +552,12 @@ export default class ProjectViewView extends Vue {
|
|||||||
imageUrl = "";
|
imageUrl = "";
|
||||||
isRegistered = false;
|
isRegistered = false;
|
||||||
issuer = "";
|
issuer = "";
|
||||||
|
issuerInfoObject: {
|
||||||
|
known: boolean;
|
||||||
|
displayName: string;
|
||||||
|
profileImageUrl?: string;
|
||||||
|
} | null = null;
|
||||||
|
issuerVisibleToDids: Array<string> = [];
|
||||||
latitude = 0;
|
latitude = 0;
|
||||||
longitude = 0;
|
longitude = 0;
|
||||||
name = "";
|
name = "";
|
||||||
@@ -547,7 +565,6 @@ export default class ProjectViewView extends Vue {
|
|||||||
offersHitLimit = false;
|
offersHitLimit = false;
|
||||||
projectId = ""; // handle ID
|
projectId = ""; // handle ID
|
||||||
recentlyCheckedAndUnconfirmableJwts: string[] = [];
|
recentlyCheckedAndUnconfirmableJwts: string[] = [];
|
||||||
showDidCopy = false;
|
|
||||||
startTime = "";
|
startTime = "";
|
||||||
truncatedDesc = "";
|
truncatedDesc = "";
|
||||||
truncateLength = 40;
|
truncateLength = 40;
|
||||||
@@ -625,8 +642,17 @@ export default class ProjectViewView extends Vue {
|
|||||||
startDateTime.toLocaleTimeString();
|
startDateTime.toLocaleTimeString();
|
||||||
}
|
}
|
||||||
this.agentDid = resp.data.claim?.agent?.identifier;
|
this.agentDid = resp.data.claim?.agent?.identifier;
|
||||||
|
this.agentDidVisibleToDids =
|
||||||
|
resp.data.claim?.agent?.identifierVisibleToDids || [];
|
||||||
this.imageUrl = resp.data.claim?.image;
|
this.imageUrl = resp.data.claim?.image;
|
||||||
this.issuer = resp.data.issuer;
|
this.issuer = resp.data.issuer;
|
||||||
|
this.issuerInfoObject = serverUtil.didInfoObject(
|
||||||
|
this.issuer,
|
||||||
|
this.activeDid,
|
||||||
|
this.allMyDids,
|
||||||
|
this.allContacts,
|
||||||
|
);
|
||||||
|
this.issuerVisibleToDids = resp.data.issuerVisibleToDids || [];
|
||||||
this.name = resp.data.claim?.name || "(no name)";
|
this.name = resp.data.claim?.name || "(no name)";
|
||||||
this.description = resp.data.claim?.description || "(no description)";
|
this.description = resp.data.claim?.description || "(no description)";
|
||||||
this.truncatedDesc = this.description.slice(0, this.truncateLength);
|
this.truncatedDesc = this.description.slice(0, this.truncateLength);
|
||||||
@@ -1158,5 +1184,15 @@ export default class ProjectViewView extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openHiddenDidDialog() {
|
||||||
|
(this.$refs.hiddenDidDialog as HiddenDidDialog).open(
|
||||||
|
"creator",
|
||||||
|
this.issuerVisibleToDids,
|
||||||
|
this.allContacts,
|
||||||
|
this.activeDid,
|
||||||
|
this.allMyDids,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { test, expect } from '@playwright/test';
|
|||||||
import { importUser, createUniqueStringsArray } from './testUtils';
|
import { importUser, createUniqueStringsArray } from './testUtils';
|
||||||
|
|
||||||
test('Create 10 new projects', async ({ page }) => {
|
test('Create 10 new projects', async ({ page }) => {
|
||||||
|
test.setTimeout(40000); // Set timeout longer since it often fails at 30 seconds
|
||||||
|
|
||||||
const projectCount = 10;
|
const projectCount = 10;
|
||||||
|
|
||||||
// Standard texts
|
// Standard texts
|
||||||
|
|||||||
Reference in New Issue
Block a user