feat(magic): inline enrollment in device card, remove preflight, align flag order
This commit is contained in:
parent
abeb1462f4
commit
c6035b97d9
1
.sixth/skills/ui-ux-pro-max
Submodule
1
.sixth/skills/ui-ux-pro-max
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit b7e3af80f6e331f6fb456667b82b12cade7c9d35
|
||||||
@ -177,6 +177,89 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Inline enrollment panel -->
|
||||||
|
<div
|
||||||
|
v-if="enrollmentPhase !== 'idle'"
|
||||||
|
class="mt-4 rounded-xl bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-100 dark:border-indigo-800 p-4"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2 mb-3">
|
||||||
|
<UIcon
|
||||||
|
name="i-heroicons-arrow-path"
|
||||||
|
class="w-5 h-5 text-indigo-600 dark:text-indigo-400"
|
||||||
|
:class="{ 'animate-spin': enrollmentPhase === 'loading' || enrollmentPhase === 'checking' }"
|
||||||
|
/>
|
||||||
|
<p class="text-sm font-bold text-indigo-900 dark:text-indigo-200">
|
||||||
|
MDM-Enrollment
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Progress steps -->
|
||||||
|
<div class="flex items-center gap-2 text-xs mb-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded-full"
|
||||||
|
:class="enrollmentPhase === 'loading' ? 'bg-indigo-200 text-indigo-800 dark:bg-indigo-700 dark:text-indigo-100' : 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300'"
|
||||||
|
>
|
||||||
|
1. Profil laden
|
||||||
|
</span>
|
||||||
|
<span class="text-gray-400">→</span>
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded-full"
|
||||||
|
:class="enrollmentPhase === 'waiting' ? 'bg-indigo-200 text-indigo-800 dark:bg-indigo-700 dark:text-indigo-100' : (enrollmentPhase === 'checking' || enrollmentPhase === 'success' || enrollmentPhase === 'error') ? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'"
|
||||||
|
>
|
||||||
|
2. QR-Code scannen
|
||||||
|
</span>
|
||||||
|
<span class="text-gray-400">→</span>
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded-full"
|
||||||
|
:class="enrollmentPhase === 'checking' ? 'bg-indigo-200 text-indigo-800 dark:bg-indigo-700 dark:text-indigo-100' : enrollmentPhase === 'success' ? 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'"
|
||||||
|
>
|
||||||
|
3. Prüfen
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- QR code -->
|
||||||
|
<div v-if="enrollmentPhase === 'waiting' && enrollmentQrUrl" class="text-center space-y-3">
|
||||||
|
<div class="bg-white p-3 rounded-xl inline-block">
|
||||||
|
<img :src="enrollmentQrUrl" alt="Enrollment QR-Code" class="w-40 h-40">
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-indigo-700 dark:text-indigo-300">
|
||||||
|
Scanne den Code mit der iPhone-Kamera und installiere das Profil.
|
||||||
|
</p>
|
||||||
|
<UButton
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
:loading="enrollmentPhase === 'checking'"
|
||||||
|
@click="checkInlineEnrollment"
|
||||||
|
>
|
||||||
|
Installation prüfen
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Success / error -->
|
||||||
|
<div v-if="enrollmentPhase === 'success'" class="text-sm text-green-700 dark:text-green-300">
|
||||||
|
✓ Enrollment abgeschlossen. Das Gerät synchronisiert sich jetzt mit dem Backend.
|
||||||
|
</div>
|
||||||
|
<div v-if="enrollmentPhase === 'error'" class="text-sm text-red-700 dark:text-red-300">
|
||||||
|
✗ {{ enrollmentError || "Enrollment fehlgeschlagen" }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Logs -->
|
||||||
|
<div v-if="enrollmentLogs.length > 0" class="mt-3 text-xs bg-white/60 dark:bg-black/20 p-2 rounded overflow-auto max-h-32">
|
||||||
|
<pre class="whitespace-pre-wrap">{{ enrollmentLogs.join('\n') }}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 flex justify-end">
|
||||||
|
<UButton
|
||||||
|
size="xs"
|
||||||
|
color="neutral"
|
||||||
|
variant="ghost"
|
||||||
|
@click="closeInlineEnrollment"
|
||||||
|
>
|
||||||
|
Schließen
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 flex items-center gap-3">
|
<div class="mt-4 flex items-center gap-3">
|
||||||
<UButton
|
<UButton
|
||||||
v-if="action.to"
|
v-if="action.to"
|
||||||
@ -218,9 +301,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onMounted, ref, watch } from "vue";
|
import { computed, onMounted, ref, watch } from "vue";
|
||||||
|
import QRCode from "qrcode";
|
||||||
import type { ComputedDevice, DeviceStatus } from "~/composables/useDeviceStatus";
|
import type { ComputedDevice, DeviceStatus } from "~/composables/useDeviceStatus";
|
||||||
import { useMdmStatus } from "~/composables/useMdmStatus";
|
import { useMdmStatus } from "~/composables/useMdmStatus";
|
||||||
import { REBREAK_MDM_VERSION, getInstalledMdmVersion, type IphoneDeviceState } from "~/composables/useTauri";
|
import { useTauri, REBREAK_MDM_VERSION, getInstalledMdmVersion, type IphoneDeviceState, type LocalServerInfo } from "~/composables/useTauri";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
device: ComputedDevice;
|
device: ComputedDevice;
|
||||||
@ -248,6 +332,20 @@ const manualSyncing = ref(false);
|
|||||||
const autoSyncing = ref(false);
|
const autoSyncing = ref(false);
|
||||||
const autoSyncComplete = ref(false);
|
const autoSyncComplete = ref(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
downloadAndPatchEnrollmentProfile,
|
||||||
|
startLocalProfileServer,
|
||||||
|
stopLocalProfileServer,
|
||||||
|
getInstalledProfiles,
|
||||||
|
mdmPush,
|
||||||
|
} = useTauri();
|
||||||
|
|
||||||
|
const enrollmentPhase = ref<"idle" | "loading" | "waiting" | "checking" | "success" | "error">("idle");
|
||||||
|
const enrollmentServerInfo = ref<LocalServerInfo | null>(null);
|
||||||
|
const enrollmentQrUrl = ref<string>("");
|
||||||
|
const enrollmentError = ref<string | null>(null);
|
||||||
|
const enrollmentLogs = ref<string[]>([]);
|
||||||
|
|
||||||
const localEnrollment = computed(() =>
|
const localEnrollment = computed(() =>
|
||||||
props.iphone?.installedProfileIDs?.includes(ENROLLMENT_PROFILE_ID) ?? false,
|
props.iphone?.installedProfileIDs?.includes(ENROLLMENT_PROFILE_ID) ?? false,
|
||||||
);
|
);
|
||||||
@ -314,16 +412,16 @@ const localRows = computed(() => {
|
|||||||
const iphone = props.iphone;
|
const iphone = props.iphone;
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: "Supervised",
|
label: "Enrollment",
|
||||||
value: iphone.isSupervised ? "Ja" : "Nein",
|
value: localEnrollment.value ? "Ja" : "Nein",
|
||||||
valueClass: iphone.isSupervised
|
valueClass: localEnrollment.value
|
||||||
? "text-green-600 dark:text-green-400 font-medium"
|
? "text-green-600 dark:text-green-400 font-medium"
|
||||||
: "text-red-600 dark:text-red-400 font-medium",
|
: "text-red-600 dark:text-red-400 font-medium",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Enrollment",
|
label: "Supervised",
|
||||||
value: localEnrollment.value ? "Ja" : "Nein",
|
value: iphone.isSupervised ? "Ja" : "Nein",
|
||||||
valueClass: localEnrollment.value
|
valueClass: iphone.isSupervised
|
||||||
? "text-green-600 dark:text-green-400 font-medium"
|
? "text-green-600 dark:text-green-400 font-medium"
|
||||||
: "text-red-600 dark:text-red-400 font-medium",
|
: "text-red-600 dark:text-red-400 font-medium",
|
||||||
},
|
},
|
||||||
@ -479,6 +577,15 @@ const action = computed<IosAction>(() => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enrollmentPhase.value !== "idle") {
|
||||||
|
return {
|
||||||
|
label: "Enrollment läuft…",
|
||||||
|
icon: "i-heroicons-arrow-path",
|
||||||
|
color: "neutral",
|
||||||
|
variant: "soft",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!props.isConnected || !props.iphone) {
|
if (!props.isConnected || !props.iphone) {
|
||||||
return {
|
return {
|
||||||
label: "iPhone verbinden, um ReBreak Cloud zu synchronisieren",
|
label: "iPhone verbinden, um ReBreak Cloud zu synchronisieren",
|
||||||
@ -512,12 +619,20 @@ const action = computed<IosAction>(() => {
|
|||||||
|
|
||||||
if (!backend?.enrolled || !localEnrollment.value) {
|
if (!backend?.enrolled || !localEnrollment.value) {
|
||||||
const isKnownDevice = !!props.device.mdmId;
|
const isKnownDevice = !!props.device.mdmId;
|
||||||
|
if (isKnownDevice) {
|
||||||
|
return {
|
||||||
|
label: "Enrollment starten",
|
||||||
|
icon: "i-heroicons-document-check",
|
||||||
|
color: "primary",
|
||||||
|
variant: "solid",
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
label: isKnownDevice ? "Schutz vervollständigen" : "Enrollen",
|
label: "Enrollen",
|
||||||
icon: isKnownDevice ? "i-heroicons-shield-check" : "i-heroicons-document-check",
|
icon: "i-heroicons-document-check",
|
||||||
color: "primary",
|
color: "primary",
|
||||||
variant: "solid",
|
variant: "solid",
|
||||||
to: isKnownDevice ? "/preflight" : "/enroll",
|
to: "/enroll",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,10 +742,86 @@ function onActionClick() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const backend = mdmState.value.data;
|
||||||
|
if (props.device.mdmId && (!backend?.enrolled || !localEnrollment.value)) {
|
||||||
|
startInlineEnrollment();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
manualSyncing.value = true;
|
manualSyncing.value = true;
|
||||||
emit("sync", props.device);
|
emit("sync", props.device);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
manualSyncing.value = false;
|
manualSyncing.value = false;
|
||||||
}, 800);
|
}, 800);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function startInlineEnrollment() {
|
||||||
|
if (!props.iphone?.udid) return;
|
||||||
|
|
||||||
|
enrollmentPhase.value = "loading";
|
||||||
|
enrollmentError.value = null;
|
||||||
|
enrollmentLogs.value = [];
|
||||||
|
enrollmentQrUrl.value = "";
|
||||||
|
enrollmentServerInfo.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const url = "https://mdm.rebreak.org/enrollment/rebreak-enrollment.mobileconfig";
|
||||||
|
enrollmentLogs.value.push(`→ Lade Enrollment-Profil`);
|
||||||
|
const path = await downloadAndPatchEnrollmentProfile(url, props.iphone.udid);
|
||||||
|
enrollmentLogs.value.push(`✓ Profil gespeichert`);
|
||||||
|
|
||||||
|
enrollmentServerInfo.value = await startLocalProfileServer(path);
|
||||||
|
enrollmentLogs.value.push(`✓ Lokaler Server gestartet`);
|
||||||
|
|
||||||
|
enrollmentQrUrl.value = await QRCode.toDataURL(enrollmentServerInfo.value.qr_payload, {
|
||||||
|
width: 192,
|
||||||
|
margin: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
enrollmentPhase.value = "waiting";
|
||||||
|
} catch (e: any) {
|
||||||
|
enrollmentError.value = e?.message ?? "Enrollment konnte nicht gestartet werden";
|
||||||
|
enrollmentLogs.value.push(`✗ ${enrollmentError.value}`);
|
||||||
|
enrollmentPhase.value = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkInlineEnrollment() {
|
||||||
|
if (!props.iphone?.udid) return;
|
||||||
|
|
||||||
|
enrollmentPhase.value = "checking";
|
||||||
|
enrollmentError.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ids = await getInstalledProfiles();
|
||||||
|
if (props.iphone) {
|
||||||
|
props.iphone.installedProfileIDs = ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ids.includes(ENROLLMENT_PROFILE_ID)) {
|
||||||
|
enrollmentError.value = "Enrollment-Profil noch nicht installiert. Bitte QR-Code scannen und Profil installieren.";
|
||||||
|
enrollmentPhase.value = "error";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enrollmentLogs.value.push("✓ Enrollment-Profil erkannt");
|
||||||
|
const push = await mdmPush(props.iphone.udid);
|
||||||
|
enrollmentLogs.value.push(`✓ Push: ${push.push_result}`);
|
||||||
|
|
||||||
|
await refreshMdmStatus();
|
||||||
|
enrollmentPhase.value = "success";
|
||||||
|
} catch (e: any) {
|
||||||
|
enrollmentError.value = e?.message ?? "Prüfung fehlgeschlagen";
|
||||||
|
enrollmentLogs.value.push(`✗ ${enrollmentError.value}`);
|
||||||
|
enrollmentPhase.value = "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeInlineEnrollment() {
|
||||||
|
stopLocalProfileServer();
|
||||||
|
enrollmentPhase.value = "idle";
|
||||||
|
enrollmentServerInfo.value = null;
|
||||||
|
enrollmentQrUrl.value = "";
|
||||||
|
enrollmentError.value = null;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
<template>
|
|
||||||
<button
|
|
||||||
class="w-full text-left"
|
|
||||||
@click="toggle"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-start gap-3 p-4 rounded-xl transition-colors"
|
|
||||||
:class="checked || auto ? 'bg-green-50/50 ring-1 ring-green-100' : 'bg-gray-50 hover:bg-gray-100'"
|
|
||||||
>
|
|
||||||
<UIcon
|
|
||||||
:name="checked || auto ? 'i-heroicons-check-circle-solid' : 'i-heroicons-circle'"
|
|
||||||
class="w-6 h-6 shrink-0"
|
|
||||||
:class="checked || auto ? 'text-green-600' : 'text-gray-400'"
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<div class="font-bold text-gray-900">{{ title }}</div>
|
|
||||||
<div class="text-sm text-gray-500 mt-0.5">{{ detail }}</div>
|
|
||||||
<div v-if="auto && !checked" class="text-xs text-green-600 font-semibold mt-1">
|
|
||||||
Automatisch erkannt ✓
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
const props = defineProps<{
|
|
||||||
modelValue: boolean;
|
|
||||||
title: string;
|
|
||||||
detail: string;
|
|
||||||
auto?: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: "update:modelValue", value: boolean): void;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const checked = computed(() => props.modelValue || props.auto);
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
emit("update:modelValue", !props.modelValue);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@ -97,7 +97,7 @@
|
|||||||
Zurück
|
Zurück
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
to="/preflight"
|
to="/supervise"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
:disabled="!iphone"
|
:disabled="!iphone"
|
||||||
|
|||||||
@ -1,79 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="min-h-screen flex flex-col items-center justify-center bg-gray-50 p-6">
|
|
||||||
<div class="max-w-md w-full space-y-6">
|
|
||||||
<div class="text-center">
|
|
||||||
<h1 class="text-2xl font-bold text-gray-900">Pre-Flight Check</h1>
|
|
||||||
<p class="text-gray-600 mt-2">
|
|
||||||
Bevor wir dein iPhone supervisieren, müssen ein paar Apple-Sicherheitschecks erledigt sein.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<UCard>
|
|
||||||
<div class="space-y-3">
|
|
||||||
<PreflightItem
|
|
||||||
v-model="checks.fmi"
|
|
||||||
title="Find My iPhone deaktiviert"
|
|
||||||
detail="Settings → [Apple-ID] → Wo ist? → Mein iPhone suchen → AUS. Ohne das blockiert Apple das Supervisieren."
|
|
||||||
:auto="iphone?.findMyEnabled === false"
|
|
||||||
/>
|
|
||||||
<PreflightItem
|
|
||||||
v-model="checks.sdp"
|
|
||||||
title="Stolen Device Protection ausgeschaltet"
|
|
||||||
detail="Settings → Face ID & Code → Schutz für gestohlene Geräte → AUS. SDP zwingt FMI an."
|
|
||||||
/>
|
|
||||||
<PreflightItem
|
|
||||||
v-model="checks.appleId"
|
|
||||||
title="Apple-ID-Passwort griffbereit"
|
|
||||||
detail="Apple fragt evtl. dein Apple-ID-PW während des FMI-Toggles ab."
|
|
||||||
/>
|
|
||||||
<PreflightItem
|
|
||||||
v-model="checks.appInstalled"
|
|
||||||
title="ReBreak-App ist auf dem iPhone installiert"
|
|
||||||
detail="Über TestFlight. Erst danach kann der Wizard die App in den Managed-State versetzen."
|
|
||||||
:auto="hasReBreakApp"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</UCard>
|
|
||||||
|
|
||||||
<div class="flex justify-between">
|
|
||||||
<UButton to="/detect" variant="ghost" color="neutral">
|
|
||||||
Zurück
|
|
||||||
</UButton>
|
|
||||||
<UButton
|
|
||||||
to="/supervise"
|
|
||||||
variant="solid"
|
|
||||||
color="primary"
|
|
||||||
:disabled="!allChecked"
|
|
||||||
>
|
|
||||||
Supervisieren starten →
|
|
||||||
</UButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed } from "vue";
|
|
||||||
import { useIphoneDevice } from "~/composables/useMagicState";
|
|
||||||
import PreflightItem from "~/components/PreflightItem.vue";
|
|
||||||
|
|
||||||
const iphone = useIphoneDevice();
|
|
||||||
|
|
||||||
const checks = ref({
|
|
||||||
fmi: false,
|
|
||||||
sdp: false,
|
|
||||||
appleId: false,
|
|
||||||
appInstalled: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const hasReBreakApp = computed(() =>
|
|
||||||
iphone.value?.installedAppBundleIDs?.includes("org.rebreak.app") ?? false,
|
|
||||||
);
|
|
||||||
|
|
||||||
const allChecked = computed(() =>
|
|
||||||
(checks.value.fmi || iphone.value?.findMyEnabled === false) &&
|
|
||||||
checks.value.sdp &&
|
|
||||||
checks.value.appleId &&
|
|
||||||
(checks.value.appInstalled || hasReBreakApp.value),
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
@ -54,7 +54,7 @@
|
|||||||
</UCard>
|
</UCard>
|
||||||
|
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<UButton to="/preflight" variant="ghost" color="neutral">
|
<UButton to="/" variant="ghost" color="neutral">
|
||||||
Zurück
|
Zurück
|
||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Graph Report - rebreak-monorepo (2026-06-18)
|
# Graph Report - rebreak-monorepo (2026-06-18)
|
||||||
|
|
||||||
## Corpus Check
|
## Corpus Check
|
||||||
- 1526 files · ~1,868,068 words
|
- 1526 files · ~1,868,054 words
|
||||||
- Verdict: corpus is large enough that graph structure adds value.
|
- Verdict: corpus is large enough that graph structure adds value.
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
@ -10,7 +10,7 @@
|
|||||||
- Token cost: 0 input · 0 output
|
- Token cost: 0 input · 0 output
|
||||||
|
|
||||||
## Graph Freshness
|
## Graph Freshness
|
||||||
- Built from commit: `0efdf2f8`
|
- Built from commit: `709f8cb3`
|
||||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||||
- Run `graphify update .` after code changes (no API cost).
|
- Run `graphify update .` after code changes (no API cost).
|
||||||
|
|
||||||
@ -5700,11 +5700,11 @@ Nodes (3): ShellScopeEntryAllowedArgs, anyOf, description
|
|||||||
_Questions this graph is uniquely positioned to answer:_
|
_Questions this graph is uniquely positioned to answer:_
|
||||||
|
|
||||||
- **Why does `Notification` connect `Community 93` to `Debug & Dev Tools`, `Community 39`, `i18n: Pricing Strings`, `i18n: Pricing Strings`, `Community 181`, `Community 53`?**
|
- **Why does `Notification` connect `Community 93` to `Debug & Dev Tools`, `Community 39`, `i18n: Pricing Strings`, `i18n: Pricing Strings`, `Community 181`, `Community 53`?**
|
||||||
_High betweenness centrality (0.032) - this node is a cross-community bridge._
|
_High betweenness centrality (0.038) - this node is a cross-community bridge._
|
||||||
- **Why does `useColors()` connect `Community 53` to `Backend API Routes`, `Community 1030`, `Consent & Magic API Routes`, `i18n: Pricing Strings`, `App Root Layout & Shell`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 27`, `Community 413`, `Community 34`, `Community 37`, `Community 426`, `Community 686`, `Community 437`, `Community 54`, `Community 80`, `Community 93`, `Community 95`, `Community 865`, `Community 872`, `Community 616`?**
|
- **Why does `useColors()` connect `Community 53` to `Backend API Routes`, `Community 1030`, `Consent & Magic API Routes`, `i18n: Pricing Strings`, `App Root Layout & Shell`, `Community 18`, `Community 20`, `Community 21`, `Community 22`, `Community 27`, `Community 413`, `Community 34`, `Community 37`, `Community 426`, `Community 686`, `Community 437`, `Community 54`, `Community 80`, `Community 93`, `Community 95`, `Community 865`, `Community 872`, `Community 616`?**
|
||||||
_High betweenness centrality (0.032) - this node is a cross-community bridge._
|
_High betweenness centrality (0.036) - this node is a cross-community bridge._
|
||||||
- **Why does `usePrisma()` connect `Debug & Dev Tools` to `Community 384`, `Community 257`, `Community 385`, `Backend API Routes`, `Backend Tests & Auth Routes`, `Android DNS Filter (Kotlin)`, `Community 32`, `Community 33`, `Community 39`, `Community 937`, `Community 47`, `Community 181`, `Community 566`, `Community 62`, `Community 68`, `Community 69`, `Community 80`, `Community 93`, `Community 244`, `Community 127`?**
|
- **Why does `Error` connect `Community 396` to `Community 290`, `Community 355`, `Community 419`, `Community 67`, `Community 263`, `Community 74`, `Community 876`, `Community 109`, `Community 81`, `Community 883`, `Community 212`, `Community 213`, `Community 117`, `Community 438`, `Community 122`, `Community 254`, `Community 607`?**
|
||||||
_High betweenness centrality (0.025) - this node is a cross-community bridge._
|
_High betweenness centrality (0.031) - this node is a cross-community bridge._
|
||||||
- **Are the 2 inferred relationships involving `usePrisma()` (e.g. with `runRevoke()` and `requireUser()`) actually correct?**
|
- **Are the 2 inferred relationships involving `usePrisma()` (e.g. with `runRevoke()` and `requireUser()`) actually correct?**
|
||||||
_`usePrisma()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
_`usePrisma()` has 2 INFERRED edges - model-reasoned connections that need verification._
|
||||||
- **What connects `deviceIdRef`, `{ state: mdmState, refresh: refreshMdmStatus }`, `manualSyncing` to the rest of the system?**
|
- **What connects `deviceIdRef`, `{ state: mdmState, refresh: refreshMdmStatus }`, `manualSyncing` to the rest of the system?**
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -8470,8 +8470,8 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/IosDeviceCard.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/IosDeviceCard.vue": {
|
||||||
"mtime": 1781756877.0845668,
|
"mtime": 1781760166.407032,
|
||||||
"ast_hash": "6d8059a60590b33fc238b2d3012cb3ee",
|
"ast_hash": "594b640f925dd262380a953908ec2e53",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/IosDeviceSection.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/IosDeviceSection.vue": {
|
||||||
@ -9070,8 +9070,8 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/backend/server/api/magic/devices/[deviceId]/mdm.get.ts": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/backend/server/api/magic/devices/[deviceId]/mdm.get.ts": {
|
||||||
"mtime": 1781758009.6469717,
|
"mtime": 1781759183.6660445,
|
||||||
"ast_hash": "b0a1b76bdc305c925326f6787aebbe11",
|
"ast_hash": "e1c779f82c164aaf5dfe1b55f6f0eaca",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/backend/server/api/magic/devices/[deviceId]/mdm-link.post.ts": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/backend/server/api/magic/devices/[deviceId]/mdm-link.post.ts": {
|
||||||
@ -9134,11 +9134,6 @@
|
|||||||
"ast_hash": "793e67cb3bfa5b6eaac5b50c74cde28b",
|
"ast_hash": "793e67cb3bfa5b6eaac5b50c74cde28b",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/PreflightItem.vue": {
|
|
||||||
"mtime": 1781729471.357726,
|
|
||||||
"ast_hash": "654d7bdac2f3c7e4909a13ee00ac3c37",
|
|
||||||
"semantic_hash": ""
|
|
||||||
},
|
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/StepButton.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/components/StepButton.vue": {
|
||||||
"mtime": 1781729471.3821392,
|
"mtime": 1781729471.3821392,
|
||||||
"ast_hash": "5ff0e5638aa149c647921ab6687b5ea8",
|
"ast_hash": "5ff0e5638aa149c647921ab6687b5ea8",
|
||||||
@ -9160,8 +9155,8 @@
|
|||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/detect.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/detect.vue": {
|
||||||
"mtime": 1781729471.4505167,
|
"mtime": 1781759990.788815,
|
||||||
"ast_hash": "70c0a0b1b507a92cfb06e0c980b23b8f",
|
"ast_hash": "eee90e00189e22dd8c99eccf5b7598a5",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/desktop-enroll.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/desktop-enroll.vue": {
|
||||||
@ -9189,14 +9184,9 @@
|
|||||||
"ast_hash": "19f47d384164a9f9e4cceacd3161e5c0",
|
"ast_hash": "19f47d384164a9f9e4cceacd3161e5c0",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/preflight.vue": {
|
|
||||||
"mtime": 1781729471.51261,
|
|
||||||
"ast_hash": "8cbd20d4fcc93d5228d6ac58bfca2c89",
|
|
||||||
"semantic_hash": ""
|
|
||||||
},
|
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/supervise.vue": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/app/pages/supervise.vue": {
|
||||||
"mtime": 1781729471.5354013,
|
"mtime": 1781759990.7880056,
|
||||||
"ast_hash": "113ce0ab42e4e160b3276e008f99a913",
|
"ast_hash": "e00cf0b40d94df6eb80dfec34ff1b323",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
},
|
},
|
||||||
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/src-tauri/tauri.conf.json": {
|
"/Users/chahinebrini/mono/rebreak-monorepo/apps/rebreak-magic/src-tauri/tauri.conf.json": {
|
||||||
@ -9338,5 +9328,10 @@
|
|||||||
"mtime": 1781748641.7178783,
|
"mtime": 1781748641.7178783,
|
||||||
"ast_hash": "22842b3019c2bb3175d475e92b437109",
|
"ast_hash": "22842b3019c2bb3175d475e92b437109",
|
||||||
"semantic_hash": ""
|
"semantic_hash": ""
|
||||||
|
},
|
||||||
|
"/Users/chahinebrini/mono/rebreak-monorepo/.woodpecker.yml": {
|
||||||
|
"mtime": 1781760270.0506988,
|
||||||
|
"ast_hash": "52e575610d792dfc647b067ecdb518b5",
|
||||||
|
"semantic_hash": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user