add a toggle for generate-embeddings flags for admins, and label DID actions
This commit is contained in:
@@ -138,92 +138,110 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex justify-between mt-4">
|
<div class="flex justify-between mt-4">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div v-if="activeDid" class="flex justify-between">
|
<div v-if="activeDid" class="flex justify-between items-end">
|
||||||
<div>
|
<div class="flex items-end gap-1">
|
||||||
<button
|
<div
|
||||||
v-if="
|
|
||||||
contactFromDid?.seesMe && contactFromDid.did !== activeDid
|
|
||||||
"
|
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
|
||||||
title="They can see your activity"
|
|
||||||
@click="confirmSetVisibility(contactFromDid, false)"
|
|
||||||
>
|
|
||||||
<font-awesome icon="arrow-up" class="fa-fw" />
|
|
||||||
<font-awesome icon="eye" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-else-if="
|
|
||||||
!contactFromDid?.seesMe && contactFromDid?.did !== activeDid
|
|
||||||
"
|
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
|
||||||
title="They cannot see your activity"
|
|
||||||
@click="confirmSetVisibility(contactFromDid, true)"
|
|
||||||
>
|
|
||||||
<font-awesome icon="arrow-up" class="fa-fw" />
|
|
||||||
<font-awesome icon="eye-slash" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-if="
|
|
||||||
contactFromDid?.iViewContent &&
|
|
||||||
contactFromDid.did !== activeDid
|
|
||||||
"
|
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
|
||||||
title="You watch their activity"
|
|
||||||
@click="confirmViewContent(contactFromDid, false)"
|
|
||||||
>
|
|
||||||
<font-awesome icon="arrow-down" class="fa-fw" />
|
|
||||||
<font-awesome icon="eye" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-else-if="
|
|
||||||
!contactFromDid?.iViewContent &&
|
|
||||||
contactFromDid?.did !== activeDid
|
|
||||||
"
|
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
|
||||||
title="You do not watch their activity"
|
|
||||||
@click="confirmViewContent(contactFromDid, true)"
|
|
||||||
>
|
|
||||||
<font-awesome icon="arrow-down" class="fa-fw" />
|
|
||||||
<font-awesome icon="eye-slash" class="fa-fw" />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-if="contactFromDid?.did !== activeDid"
|
v-if="contactFromDid?.did !== activeDid"
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
class="flex flex-col items-center"
|
||||||
title="Check Visibility"
|
|
||||||
@click="checkVisibility(contactFromDid)"
|
|
||||||
>
|
>
|
||||||
<font-awesome icon="rotate" class="fa-fw" />
|
<button
|
||||||
</button>
|
v-if="contactFromDid?.seesMe"
|
||||||
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="They can see your activity"
|
||||||
|
@click="confirmSetVisibility(contactFromDid, false)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="arrow-up" class="fa-fw" />
|
||||||
|
<font-awesome icon="eye" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="!contactFromDid?.seesMe"
|
||||||
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="They cannot see your activity"
|
||||||
|
@click="confirmSetVisibility(contactFromDid, true)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="arrow-up" class="fa-fw" />
|
||||||
|
<font-awesome icon="eye-slash" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<span class="text-xs text-slate-600">See You</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="contactFromDid?.did !== activeDid"
|
||||||
|
class="flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-if="contactFromDid?.iViewContent"
|
||||||
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="You watch their activity"
|
||||||
|
@click="confirmViewContent(contactFromDid, false)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="arrow-down" class="fa-fw" />
|
||||||
|
<font-awesome icon="eye" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="!contactFromDid?.iViewContent"
|
||||||
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="You do not watch their activity"
|
||||||
|
@click="confirmViewContent(contactFromDid, true)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="arrow-down" class="fa-fw" />
|
||||||
|
<font-awesome icon="eye-slash" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<span class="text-xs text-slate-600">Watch Them</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="contactFromDid?.did !== activeDid"
|
||||||
|
class="flex flex-col items-center"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="Check Visibility"
|
||||||
|
@click="checkVisibility(contactFromDid)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="rotate" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<span class="text-xs text-slate-600">Check</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<div
|
||||||
v-if="contactFromDid?.did !== activeDid"
|
v-if="contactFromDid?.did !== activeDid"
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
class="flex flex-col items-center ml-6"
|
||||||
title="Registration"
|
|
||||||
@click="confirmRegister(contactFromDid)"
|
|
||||||
>
|
>
|
||||||
<font-awesome
|
<button
|
||||||
v-if="contactFromDid?.registered"
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
icon="person-circle-check"
|
title="Registration"
|
||||||
class="fa-fw"
|
@click="confirmRegister(contactFromDid)"
|
||||||
/>
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
v-else
|
v-if="contactFromDid?.registered"
|
||||||
icon="person-circle-question"
|
icon="person-circle-check"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</button>
|
<font-awesome
|
||||||
|
v-else
|
||||||
|
icon="person-circle-question"
|
||||||
|
class="fa-fw"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span class="text-xs text-slate-600">Register</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<div
|
||||||
class="text-sm uppercase bg-gradient-to-b from-rose-500 to-rose-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-6 mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
v-if="contactFromDid?.did !== activeDid"
|
||||||
title="Delete"
|
class="flex flex-col items-center ml-6"
|
||||||
@click="confirmDeleteContact(contactFromDid)"
|
|
||||||
>
|
>
|
||||||
<font-awesome icon="trash-can" class="fa-fw" />
|
<button
|
||||||
</button>
|
class="text-sm uppercase bg-gradient-to-b from-rose-500 to-rose-800 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white mx-0.5 my-0.5 px-2 py-1.5 rounded-md"
|
||||||
|
title="Delete"
|
||||||
|
@click="confirmDeleteContact(contactFromDid)"
|
||||||
|
>
|
||||||
|
<font-awesome icon="trash-can" class="fa-fw" />
|
||||||
|
</button>
|
||||||
|
<span class="text-xs text-slate-600">Delete</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!contactFromDid?.profileImageUrl">
|
<div v-if="!contactFromDid?.profileImageUrl">
|
||||||
<div>Auto-Generated Icon</div>
|
<div>Auto-Generated Icon</div>
|
||||||
@@ -263,6 +281,40 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Only admins can set the generate-embedding flag -->
|
||||||
|
<div
|
||||||
|
v-if="showGeneralAdvanced && viewingDid"
|
||||||
|
class="mt-4 pt-4 border-t border-slate-300"
|
||||||
|
data-testid="generateEmbeddingSection"
|
||||||
|
>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Always generate embedding
|
||||||
|
</label>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
role="switch"
|
||||||
|
:aria-checked="generateEmbedding"
|
||||||
|
:disabled="generateEmbeddingSaving || generateEmbeddingLoading"
|
||||||
|
class="relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
|
:class="generateEmbedding ? 'bg-blue-600' : 'bg-gray-200'"
|
||||||
|
@click="toggleGenerateEmbedding"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition"
|
||||||
|
:class="generateEmbedding ? 'translate-x-5' : 'translate-x-1'"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<span class="text-sm text-gray-600">
|
||||||
|
{{ generateEmbedding ? "On" : "Off" }}
|
||||||
|
<span v-if="generateEmbeddingLoading" class="ml-1">(loading…)</span>
|
||||||
|
<span v-else-if="generateEmbeddingSaving" class="ml-1"
|
||||||
|
>(saving…)</span
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Loading Animation -->
|
<!-- Loading Animation -->
|
||||||
<div
|
<div
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
@@ -332,7 +384,10 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
|||||||
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 TopMessage from "../components/TopMessage.vue";
|
import TopMessage from "../components/TopMessage.vue";
|
||||||
import { NotificationIface } from "../constants/app";
|
import {
|
||||||
|
DEFAULT_PARTNER_API_SERVER,
|
||||||
|
NotificationIface,
|
||||||
|
} from "../constants/app";
|
||||||
import { Contact } from "../db/tables/contacts";
|
import { Contact } from "../db/tables/contacts";
|
||||||
import { BoundingBox } from "../db/tables/settings";
|
import { BoundingBox } from "../db/tables/settings";
|
||||||
|
|
||||||
@@ -406,11 +461,16 @@ export default class DIDView extends Vue {
|
|||||||
contactLabels: string[] = [];
|
contactLabels: string[] = [];
|
||||||
|
|
||||||
contactYaml = "";
|
contactYaml = "";
|
||||||
|
generateEmbedding: boolean | null = null;
|
||||||
|
generateEmbeddingLoading = false;
|
||||||
|
generateEmbeddingSaving = false;
|
||||||
hitEnd = false;
|
hitEnd = false;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
isMyDid = false;
|
isMyDid = false;
|
||||||
|
partnerApiServer = DEFAULT_PARTNER_API_SERVER;
|
||||||
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
||||||
showDidDetails = false;
|
showDidDetails = false;
|
||||||
|
showGeneralAdvanced = false;
|
||||||
showLargeIdenticonId?: string;
|
showLargeIdenticonId?: string;
|
||||||
showLargeIdenticonUrl?: string;
|
showLargeIdenticonUrl?: string;
|
||||||
viewingDid?: string;
|
viewingDid?: string;
|
||||||
@@ -444,6 +504,9 @@ export default class DIDView extends Vue {
|
|||||||
await this.loadContactInformation();
|
await this.loadContactInformation();
|
||||||
await this.loadClaimsAbout();
|
await this.loadClaimsAbout();
|
||||||
await this.checkIfOwnDID();
|
await this.checkIfOwnDID();
|
||||||
|
if (this.showGeneralAdvanced && this.activeDid) {
|
||||||
|
await this.loadGenerateEmbeddingState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +522,9 @@ export default class DIDView extends Vue {
|
|||||||
this.activeDid = activeIdentity.activeDid || "";
|
this.activeDid = activeIdentity.activeDid || "";
|
||||||
|
|
||||||
this.apiServer = settings.apiServer || "";
|
this.apiServer = settings.apiServer || "";
|
||||||
|
this.showGeneralAdvanced = !!settings.showGeneralAdvanced;
|
||||||
|
this.partnerApiServer =
|
||||||
|
(settings.partnerApiServer as string) || DEFAULT_PARTNER_API_SERVER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -519,6 +585,71 @@ export default class DIDView extends Vue {
|
|||||||
this.isMyDid = allAccountDids.includes(this.viewingDid);
|
this.isMyDid = allAccountDids.includes(this.viewingDid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads partner profile generateEmbedding state for the viewed DID (when showGeneralAdvanced).
|
||||||
|
*/
|
||||||
|
private async loadGenerateEmbeddingState() {
|
||||||
|
if (!this.viewingDid || !this.activeDid) return;
|
||||||
|
this.generateEmbeddingLoading = true;
|
||||||
|
try {
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
|
const url = `${this.partnerApiServer}/api/partner/userProfileForIssuer/${encodeURIComponent(this.viewingDid)}`;
|
||||||
|
const response = await this.axios.get(url, { headers });
|
||||||
|
const data = response.data?.data;
|
||||||
|
this.generateEmbedding =
|
||||||
|
data && typeof data.generateEmbedding === "boolean"
|
||||||
|
? data.generateEmbedding
|
||||||
|
: false;
|
||||||
|
} catch {
|
||||||
|
this.generateEmbedding = false;
|
||||||
|
} finally {
|
||||||
|
this.generateEmbeddingLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the "always generate embedding" flag for the viewed DID on the partner API.
|
||||||
|
* Only permissioned (admin) users can change this; API returns 403 otherwise.
|
||||||
|
*/
|
||||||
|
async toggleGenerateEmbedding() {
|
||||||
|
if (
|
||||||
|
!this.viewingDid ||
|
||||||
|
!this.activeDid ||
|
||||||
|
this.generateEmbeddingSaving ||
|
||||||
|
this.generateEmbeddingLoading
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newValue = !this.generateEmbedding;
|
||||||
|
this.generateEmbeddingSaving = true;
|
||||||
|
try {
|
||||||
|
const headers = await getHeaders(this.activeDid);
|
||||||
|
const url = `${this.partnerApiServer}/api/partner/userProfile/${encodeURIComponent(this.viewingDid)}/generateEmbedding`;
|
||||||
|
await this.axios.put(url, { generateEmbedding: newValue }, { headers });
|
||||||
|
this.generateEmbedding = newValue;
|
||||||
|
this.notify.success(
|
||||||
|
newValue
|
||||||
|
? "Contact tagged to always generate embedding."
|
||||||
|
: "Contact untagged from always generating embedding.",
|
||||||
|
TIMEOUTS.STANDARD,
|
||||||
|
);
|
||||||
|
} catch (err: unknown) {
|
||||||
|
const error = (err as { response?: { data?: { error?: string } } })
|
||||||
|
?.response?.data?.error;
|
||||||
|
if (error) {
|
||||||
|
this.notify.error(error, TIMEOUTS.LONG);
|
||||||
|
} else {
|
||||||
|
logger.error("Failed to update generate-embedding flag:", err);
|
||||||
|
this.notify.error(
|
||||||
|
"Failed to update generate-embedding flag. Try again.",
|
||||||
|
TIMEOUTS.LONG,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.generateEmbeddingSaving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads additional claims when user scrolls to bottom
|
* Loads additional claims when user scrolls to bottom
|
||||||
* Used by infinite scroll component to implement pagination
|
* Used by infinite scroll component to implement pagination
|
||||||
|
|||||||
Reference in New Issue
Block a user