diff --git a/project.task.yaml b/project.task.yaml index 9be5db07..727fabd9 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -3,6 +3,8 @@ tasks: - .5 give list of visible IDs on the claim detail page - instead of text, make links to share the data with contacts and ask for help +- Add TimeSafari as a shareable app https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target +- make a shortcut for BVC - choose an agent via a contact chooser (not just copy-paste a DID) - .5 find out why clicking quickly back-and-forth onto the "my project" page often shows error "You need an identifier to load your projects." (easier to reproduce on desktop?) - .5 bug - it didn't show the "fulfills offer" on the claim detail page for a give that had one - https://test.timesafari.app/claim/01HMFWRPA3PD6Q9EYFKX3MC41J @@ -17,7 +19,7 @@ tasks: - make the "give" on contact screen work like other give (allowing donation vs current blank) - on ClaimView, the "ask someone" should refer to "visible" IDs, or to confirmations only if confirmations are visible - notify user when data import is completed -- "send them to this page" on ClaimView should be a link (for installed app) +- message "send them to this page" on ClaimView should be a link (for installed app) - When we update a version, desktop browser users have seen nothing happen after clicking on the contact page QR and on the account page "Help"; errors show in the console. Reload fixed it. If this happens on mobile, ask the user to reload. - 01 show my VCs - most interesting, or via search @@ -122,6 +124,8 @@ tasks: - 16 From the home screen, make the quick action even easier. - allow some gives even if they aren't registered - maybe someday as a gift to the world, but we really want this to be built via personal connections +- .1 When Chrome shows compatibility https://developer.mozilla.org/en-US/docs/Web/API/Web_Share_API#api.navigator.canshare + then change the canShare check in this app to check the real canShare() method. log: - videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29 diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 5fe16c8a..fa4c8558 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -174,21 +174,21 @@ export function isEmptyOrHiddenDid(did?: string) { * Similar logic is found in endorser-mobile. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any -function testRecursivelyOnString(func: (arg0: any) => boolean, input: any) { +function testRecursivelyOnStrings(func: (arg0: any) => boolean, input: any) { if (Object.prototype.toString.call(input) === "[object String]") { return func(input); } else if (input instanceof Object) { if (!Array.isArray(input)) { // it's an object for (const key in input) { - if (testRecursivelyOnString(func, input[key])) { + if (testRecursivelyOnStrings(func, input[key])) { return true; } } } else { // it's an array for (const value of input) { - if (testRecursivelyOnString(func, value)) { + if (testRecursivelyOnStrings(func, value)) { return true; } } @@ -201,7 +201,7 @@ function testRecursivelyOnString(func: (arg0: any) => boolean, input: any) { // eslint-disable-next-line @typescript-eslint/no-explicit-any export function containsHiddenDid(obj: any) { - return testRecursivelyOnString(isHiddenDid, obj); + return testRecursivelyOnStrings(isHiddenDid, obj); } export function stripEndorserPrefix(claimId: string) { diff --git a/src/libs/util.ts b/src/libs/util.ts index 63f539d0..d1174637 100644 --- a/src/libs/util.ts +++ b/src/libs/util.ts @@ -99,13 +99,17 @@ export const canFulfillOffer = (veriClaim: GenericServerRecord) => { export function findAllVisibleToDids( // eslint-disable-next-line @typescript-eslint/no-explicit-any input: any, + humanReadable = false, ): Record> { if (Array.isArray(input)) { const result: Record> = {}; for (let i = 0; i < input.length; i++) { - const inside = findAllVisibleToDids(input[i]); + const inside = findAllVisibleToDids(input[i], humanReadable); for (const key in inside) { - result["[" + i + "]" + key] = inside[key]; + const pathKey = humanReadable + ? "#" + (i + 1) + " " + key + : "[" + i + "]" + key; + result[pathKey] = inside[key]; } } return result; @@ -115,11 +119,15 @@ export function findAllVisibleToDids( for (const key in input) { if (key.endsWith("VisibleToDids")) { const newKey = key.slice(0, -"VisibleToDids".length); - result["." + newKey] = input[key]; + const pathKey = humanReadable ? newKey : "." + newKey; + result[pathKey] = input[key]; } else { - const inside = findAllVisibleToDids(input[key]); + const inside = findAllVisibleToDids(input[key], humanReadable); for (const insideKey in inside) { - result["." + key + insideKey] = inside[insideKey]; + const pathKey = humanReadable + ? key + "'s " + insideKey + : "." + key + insideKey; + result[pathKey] = inside[insideKey]; } } } @@ -135,7 +143,10 @@ export function findAllVisibleToDids( pkgx +deno.land sh + deno + import * as R from 'ramda'; + //import { findAllVisibleToDids } from './src/libs/util'; // doesn't work because other dependencies fail so gotta copy-and-paste function console.log(R.equals(findAllVisibleToDids(null), {})); console.log(R.equals(findAllVisibleToDids(9), {})); diff --git a/src/main.ts b/src/main.ts index 075126f7..fc0152a8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -46,6 +46,7 @@ import { faLongArrowAltRight, faMagnifyingGlass, faMessage, + faMinus, faPen, faPersonCircleCheck, faPersonCircleQuestion, @@ -101,6 +102,7 @@ library.add( faLongArrowAltRight, faMagnifyingGlass, faMessage, + faMinus, faPen, faPersonCircleCheck, faPersonCircleQuestion, diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index f6b4c7c9..fadba586 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -469,6 +469,7 @@ import { AxiosError, AxiosRequestConfig } from "axios"; import Dexie from "dexie"; import "dexie-export-import"; +import { ImportProgress } from "dexie-export-import/dist/import"; import { ref } from "vue"; import { Component, Vue } from "vue-facing-decorator"; import { useClipboard } from "@vueuse/core"; @@ -481,7 +482,6 @@ import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { accessToken } from "@/libs/crypto"; import { IIdentifier } from "@veramo/core"; import { ErrorResponse, RateLimits } from "@/libs/endorserServer"; -import { ImportProgress } from "dexie-export-import/dist/import"; // eslint-disable-next-line @typescript-eslint/no-var-requires const Buffer = require("buffer/").Buffer; @@ -526,14 +526,11 @@ export default class AccountViewView extends Vue { limitsMessage = ""; loadingLimits = true; // might as well now that we do it on mount, to avoid flashing the registration message showContactGives = false; - showDidCopy = false; showDerCopy = false; showB64Copy = false; showPubCopy = false; - showAdvanced = false; - subscription: PushSubscription | null = null; warnIfProdServer = false; warnIfTestServer = false; diff --git a/src/views/ClaimView.vue b/src/views/ClaimView.vue index f32f0d52..1b9f24d7 100644 --- a/src/views/ClaimView.vue +++ b/src/views/ClaimView.vue @@ -235,29 +235,87 @@
-

Visible Details

-
+

+ {{ serverUtil.containsHiddenDid(veriClaim) ? "Visible " : "" }}Details +

+
+ Some of the details are not visible to you; they show as "HIDDEN". They + are not visible to any of your direct contacts, either. + + If you'd like to ask any of your contacts to take a look and see if + their contacts can see more details, + click to send them this info + and see if they are willing to make an introduction. + + + If you'd like to ask any of your contacts to take a look and see if + their contacts can see more details, + share this page with them + and see if they are willing to make an introduction. + +
+ +
Some of the details are not visible to you but they are visible to some - of your contacts. If you'd like an introduction, share the information - with them and ask them to connect you. + of your contacts. + + If you'd like an introduction, + click to share the information with them and ask if they'll tell + you more about the participants. + + + If you'd like an introduction, + share this page with them and ask if they'll tell you more about + about the participants. + +
-
- {{ visibleDidPath }} +
+ + The {{ visibleDidPath }} is visible to:
-
+
@@ -308,6 +366,7 @@ import * as yaml from "js-yaml"; import * as R from "ramda"; import { IIdentifier } from "@veramo/core"; import { Component, Vue } from "vue-facing-decorator"; +import { useClipboard } from "@vueuse/core"; import GiftedDialog from "@/components/GiftedDialog.vue"; import OfferDialog from "@/components/OfferDialog.vue"; @@ -341,6 +400,7 @@ export default class ClaimView extends Vue { allContacts: Array = []; apiServer = ""; + canShare = false; confirmerIdList: string[] = []; // list of DIDs that have confirmed this claim excluding the issuer confsVisibleErrorMessage = ""; confsVisibleToIdList: string[] = []; // list of DIDs that can see any confirmer @@ -355,7 +415,9 @@ export default class ClaimView extends Vue { veriClaim = serverUtil.BLANK_GENERIC_SERVER_RECORD; veriClaimDump = ""; veriClaimDidsVisible = {}; + windowLocation = window.location.href; + R = R; yaml = yaml; libsUtil = libsUtil; serverUtil = serverUtil; @@ -405,6 +467,10 @@ export default class ClaimView extends Vue { -1, ); } + + // 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; } // insert a space before any capital letters except the initial letter @@ -472,6 +538,7 @@ export default class ClaimView extends Vue { this.veriClaimDump = yaml.dump(this.veriClaim); this.veriClaimDidsVisible = libsUtil.findAllVisibleToDids( this.veriClaim, + true, ); } else { // actually, axios typically throws an error so we never get here @@ -688,5 +755,29 @@ export default class ClaimView extends Vue { this.veriClaim.handleId, ); } + + copyToClipboard(text: string) { + useClipboard() + .copy(text) + .then(() => { + this.$notify( + { + group: "alert", + type: "toast", + title: "Copied", + text: "Location was copied to clipboard.", + }, + 2000, + ); + }); + } + + onClickShareClaim() { + window.navigator.share({ + title: "Help Connect Me", + text: "I'm trying to find the full details of this claim. Can you help me?", + url: this.windowLocation, + }); + } }