More refactoring
This commit is contained in:
parent
f911e763ff
commit
b0190b2ccf
@ -1,5 +0,0 @@
|
||||
{
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
],
|
||||
}
|
BIN
package-lock.json
generated
BIN
package-lock.json
generated
Binary file not shown.
@ -18,7 +18,8 @@
|
||||
"@vueuse/components": "^10.2.1",
|
||||
"@vueuse/core": "^10.2.1",
|
||||
"font-awesome": "^4.7.0",
|
||||
"vue": "^3.4.29"
|
||||
"vue": "^3.4.29",
|
||||
"vue-router": "^4.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
@ -75,7 +76,8 @@
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"one-var": [ "error", "never" ]
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
|
13
src/App.vue
13
src/App.vue
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div id="app" v-if="user">
|
||||
<div id="app" v-if="!user">
|
||||
<login-view />
|
||||
</div>
|
||||
<div id="app" v-else>
|
||||
<nav-bar
|
||||
v-model:treeOpen="treeOpen"
|
||||
:dn="activeDn"
|
||||
@ -62,11 +65,12 @@ import { onMounted, provide, ref, watch } from "vue";
|
||||
import AttributeCard from "./components/schema/AttributeCard.vue";
|
||||
import EntryEditor from "./components/editor/EntryEditor.vue";
|
||||
import { LdapSchema } from "./components/schema/schema";
|
||||
import LdifImportDialog from "./components/LdifImportDialog.vue";
|
||||
import LdifImportDialog from "@/views/dialogs/LdifImportDialog.vue";
|
||||
import NavBar from "./components/NavBar.vue";
|
||||
import ObjectClassCard from "./components/schema/ObjectClassCard.vue";
|
||||
import type { Provided } from "./components/Provided";
|
||||
import type { Provided } from "@/data/provided";
|
||||
import TreeView from "./components/TreeView.vue";
|
||||
import LoginView from "@/views/LoginView.vue";
|
||||
|
||||
interface Error {
|
||||
counter: number;
|
||||
@ -100,7 +104,7 @@ const provided: Provided = {
|
||||
showInfo,
|
||||
showException,
|
||||
showWarning,
|
||||
authHeaders
|
||||
authHeaders,
|
||||
};
|
||||
|
||||
provide("app", provided);
|
||||
@ -204,3 +208,4 @@ select {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
./data/Provided
|
||||
|
@ -69,20 +69,20 @@
|
||||
<script setup lang="ts">
|
||||
import { inject, nextTick, ref } from "vue";
|
||||
import DropdownMenu from "./ui/DropdownMenu.vue";
|
||||
import type { Provided } from "./Provided";
|
||||
import type { Provided } from "@/data/provided";
|
||||
import NodeLabel from "./NodeLabel.vue";
|
||||
import SearchResults from "./SearchResults.vue";
|
||||
|
||||
const app = inject<Provided>("app"),
|
||||
input = ref<HTMLInputElement | null>(null),
|
||||
query = ref(""),
|
||||
collapsed = ref(false),
|
||||
emit = defineEmits([
|
||||
"select-dn",
|
||||
"show-modal",
|
||||
"show-oc",
|
||||
"update:treeOpen",
|
||||
]);
|
||||
const app = inject<Provided>("app");
|
||||
const input = ref<HTMLInputElement | null>(null);
|
||||
const query = ref("");
|
||||
const collapsed = ref(false);
|
||||
const emit = defineEmits([
|
||||
"select-dn",
|
||||
"show-modal",
|
||||
"show-oc",
|
||||
"update:treeOpen",
|
||||
]);
|
||||
|
||||
defineProps({
|
||||
baseDn: String,
|
||||
|
@ -12,35 +12,35 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
const props = defineProps({
|
||||
dn: String,
|
||||
oc: String,
|
||||
}),
|
||||
icons: { [key: string]: string } = {
|
||||
// OC -> icon mapping
|
||||
account: "user",
|
||||
groupOfNames: "users",
|
||||
groupOfURLs: "users",
|
||||
groupOfUniqueNames: "users",
|
||||
inetOrgPerson: "address-book",
|
||||
krbContainer: "lock",
|
||||
krbPrincipal: "user-o",
|
||||
krbRealmContainer: "globe",
|
||||
organization: "globe",
|
||||
organizationalRole: "android",
|
||||
organizationalUnit: "sitemap",
|
||||
person: "user",
|
||||
posixGroup: "users",
|
||||
},
|
||||
icon = computed(() =>
|
||||
// Get the icon for an OC
|
||||
props.oc ? " fa-" + (icons[props.oc] || "question") : "fa-question"
|
||||
),
|
||||
// Shorten a DN for readability
|
||||
label = computed(() =>
|
||||
(props.dn || "")
|
||||
.split(",")[0]
|
||||
.replace(/^cn=/, "")
|
||||
.replace(/^krbPrincipalName=/, "")
|
||||
),
|
||||
emit = defineEmits(["select-dn"]);
|
||||
dn: String,
|
||||
oc: String,
|
||||
});
|
||||
const icons: { [key: string]: string } = {
|
||||
// OC -> icon mapping
|
||||
account: "user",
|
||||
groupOfNames: "users",
|
||||
groupOfURLs: "users",
|
||||
groupOfUniqueNames: "users",
|
||||
inetOrgPerson: "address-book",
|
||||
krbContainer: "lock",
|
||||
krbPrincipal: "user-o",
|
||||
krbRealmContainer: "globe",
|
||||
organization: "globe",
|
||||
organizationalRole: "android",
|
||||
organizationalUnit: "sitemap",
|
||||
person: "user",
|
||||
posixGroup: "users",
|
||||
};
|
||||
const icon = computed(() =>
|
||||
// Get the icon for an OC
|
||||
props.oc ? " fa-" + (icons[props.oc] || "question") : "fa-question"
|
||||
);
|
||||
// Shorten a DN for readability
|
||||
const label = computed(() =>
|
||||
(props.dn || "")
|
||||
.split(",")[0]
|
||||
.replace(/^cn=/, "")
|
||||
.replace(/^krbPrincipalName=/, "")
|
||||
);
|
||||
const emit = defineEmits(["select-dn"]);
|
||||
</script>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, nextTick, ref, watch } from "vue";
|
||||
import Popover from "./ui/Popover.vue";
|
||||
import type { Provided } from "./Provided";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
interface Result {
|
||||
dn: string;
|
||||
@ -23,31 +23,28 @@ interface Result {
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
for: String,
|
||||
label: {
|
||||
type: String,
|
||||
default: "name",
|
||||
validator: (value: string) => ["name", "dn"].includes(value),
|
||||
},
|
||||
shorten: String,
|
||||
silent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}),
|
||||
app = inject<Provided>("app"),
|
||||
results = ref<Result[]>([]),
|
||||
show = computed(
|
||||
() =>
|
||||
props.query.trim() != "" &&
|
||||
results.value &&
|
||||
results.value.length > 1
|
||||
),
|
||||
emit = defineEmits(["select-dn"]);
|
||||
query: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
for: String,
|
||||
label: {
|
||||
type: String,
|
||||
default: "name",
|
||||
validator: (value: string) => ["name", "dn"].includes(value),
|
||||
},
|
||||
shorten: String,
|
||||
silent: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
const app = inject<Provided>("app");
|
||||
const results = ref<Result[]>([]);
|
||||
const show = computed(
|
||||
() => props.query.trim() != "" && results.value && results.value.length > 1
|
||||
);
|
||||
const emit = defineEmits(["select-dn"]);
|
||||
|
||||
watch(
|
||||
() => props.query,
|
||||
|
@ -43,7 +43,7 @@
|
||||
import { DN } from "./schema/schema";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import NodeLabel from "./NodeLabel.vue";
|
||||
import type { TreeNode } from "./TreeNode";
|
||||
import type { TreeNode } from "@/data/treeNode";
|
||||
|
||||
class Node implements TreeNode {
|
||||
dn: string;
|
||||
@ -102,10 +102,10 @@ class Node implements TreeNode {
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
activeDn: String,
|
||||
}),
|
||||
tree = ref<Node>(),
|
||||
emit = defineEmits(["base-dn", "update:activeDn"]);
|
||||
activeDn: String,
|
||||
});
|
||||
const tree = ref<Node>();
|
||||
const emit = defineEmits(["base-dn", "update:activeDn"]);
|
||||
|
||||
onMounted(async () => {
|
||||
await reload("base");
|
||||
@ -134,8 +134,8 @@ watch(
|
||||
// Reveal the selected entry by opening all parents
|
||||
hierarchy.reverse();
|
||||
for (let i = 0; i < hierarchy.length; ++i) {
|
||||
const p = hierarchy[i].toString(),
|
||||
node = tree.value?.find(p);
|
||||
const p = hierarchy[i].toString();
|
||||
const node = tree.value?.find(p);
|
||||
if (!node) break;
|
||||
if (!node.loaded) await reload(p);
|
||||
node.open = true;
|
||||
|
@ -160,9 +160,9 @@
|
||||
import { Attribute, generalizedTime } from "../schema/schema";
|
||||
import { computed, inject, onMounted, onUpdated, ref, watch } from "vue";
|
||||
import AttributeSearch from "./AttributeSearch.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import SearchResults from "../SearchResults.vue";
|
||||
import ToggleButton from "../ui/ToggleButton.vue";
|
||||
import type { Provided } from "@/data/provided";
|
||||
import SearchResults from "@/components/SearchResults.vue";
|
||||
import ToggleButton from "@/components/ui/ToggleButton.vue";
|
||||
|
||||
function unique(
|
||||
element: unknown,
|
||||
@ -301,8 +301,8 @@ function validate() {
|
||||
|
||||
function update(evt: Event) {
|
||||
const target = evt.target as HTMLInputElement;
|
||||
const value = target.value,
|
||||
index = +target.id.split("-").slice(-1).pop()!;
|
||||
const value = target.value;
|
||||
const index = +target.id.split("-").slice(-1).pop()!;
|
||||
updateValue(index, value);
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { Attribute } from "../schema/schema";
|
||||
import { computed, inject, nextTick, ref, watch } from "vue";
|
||||
import Popover from "../ui/Popover.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import Popover from "@/components/ui/Popover.vue";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
const props = defineProps({
|
||||
query: { type: String, default: "" },
|
||||
|
@ -188,20 +188,20 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, nextTick, ref, watch } from "vue";
|
||||
import AddAttributeDialog from "./AddAttributeDialog.vue";
|
||||
import AddObjectClassDialog from "./AddObjectClassDialog.vue";
|
||||
import AddPhotoDialog from "./AddPhotoDialog.vue";
|
||||
import AddAttributeDialog from "@views/dialogs/AddAttributeDialog.vue";
|
||||
import AddObjectClassDialog from "@views/dialogs/AddObjectClassDialog.vue";
|
||||
import AddPhotoDialog from "@views/dialogs/AddPhotoDialog.vue";
|
||||
import AttributeRow from "./AttributeRow.vue";
|
||||
import CopyEntryDialog from "./CopyEntryDialog.vue";
|
||||
import DeleteEntryDialog from "./DeleteEntryDialog.vue";
|
||||
import DiscardEntryDialog from "./DiscardEntryDialog.vue";
|
||||
import CopyEntryDialog from "@views/dialogs/CopyEntryDialog.vue";
|
||||
import DeleteEntryDialog from "@views/dialogs/DeleteEntryDialog.vue";
|
||||
import DiscardEntryDialog from "@views/dialogs/DiscardEntryDialog.vue";
|
||||
import DropdownMenu from "../ui/DropdownMenu.vue";
|
||||
import type { Entry } from "./Entry";
|
||||
import NewEntryDialog from "./NewEntryDialog.vue";
|
||||
import type { Entry } from "@/data/entry";
|
||||
import NewEntryDialog from "@views/dialogs/NewEntryDialog.vue";
|
||||
import NodeLabel from "../NodeLabel.vue";
|
||||
import PasswordChangeDialog from "./PasswordChangeDialog.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import RenameEntryDialog from "./RenameEntryDialog.vue";
|
||||
import PasswordChangeDialog from "@views/dialogs/PasswordChangeDialog.vue";
|
||||
import type { Provided } from "@/data/provided";
|
||||
import RenameEntryDialog from "@views/dialogs/RenameEntryDialog.vue";
|
||||
|
||||
function unique(
|
||||
element: unknown,
|
||||
@ -425,8 +425,8 @@ async function ldif() {
|
||||
});
|
||||
if (!response.ok) return;
|
||||
|
||||
const a = document.createElement("a"),
|
||||
url = URL.createObjectURL(await response.blob());
|
||||
const a = document.createElement("a");
|
||||
const url = URL.createObjectURL(await response.blob());
|
||||
a.href = url;
|
||||
a.download = entry.value!.meta.dn.split(",")[0].split("=")[1] + ".ldif";
|
||||
document.body.appendChild(a);
|
||||
|
@ -30,10 +30,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from "vue";
|
||||
import Card from "../ui/Card.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
const props = defineProps({ modelValue: String }),
|
||||
app = inject<Provided>("app"),
|
||||
attr = computed(() => app?.schema?.attr(props.modelValue)),
|
||||
emit = defineEmits(["show-attr", "update:modelValue"]);
|
||||
</script>
|
||||
const props = defineProps({ modelValue: String });
|
||||
const app = inject<Provided>("app");
|
||||
const attr = computed(() => app?.schema?.attr(props.modelValue));
|
||||
const emit = defineEmits(["show-attr", "update:modelValue"]);
|
||||
</script>
|
@ -51,10 +51,10 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from "vue";
|
||||
import Card from "../ui/Card.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
const props = defineProps({ modelValue: String }),
|
||||
app = inject<Provided>("app"),
|
||||
oc = computed(() => app?.schema?.oc(props.modelValue)),
|
||||
emit = defineEmits(["show-attr", "show-oc", "update:modelValue"]);
|
||||
</script>
|
||||
const props = defineProps({ modelValue: String });
|
||||
const app = inject<Provided>("app");
|
||||
const oc = computed(() => app?.schema?.oc(props.modelValue));
|
||||
const emit = defineEmits(["show-attr", "show-oc", "update:modelValue"]);
|
||||
</script>
|
@ -6,12 +6,12 @@ const sut = new LdapSchema(json);
|
||||
|
||||
describe("LDAP schema items", () => {
|
||||
describe("DNs and RDNs", () => {
|
||||
const dn1 = new DN("dc=foo,dc=bar"),
|
||||
rdn1 = dn1.rdn;
|
||||
const dn2 = new DN("domainComponent=FOO,domainComponent=BAR"),
|
||||
rdn2 = dn2.rdn;
|
||||
const dn3 = new DN("domainComponent=bar"),
|
||||
rdn3 = dn3.rdn;
|
||||
const dn1 = new DN("dc=foo,dc=bar");
|
||||
const rdn1 = dn1.rdn;
|
||||
const dn2 = new DN("domainComponent=FOO,domainComponent=BAR");
|
||||
const rdn2 = dn2.rdn;
|
||||
const dn3 = new DN("domainComponent=bar");
|
||||
const rdn3 = dn3.rdn;
|
||||
|
||||
test("Test RDN attribute equality", () =>
|
||||
expect(rdn1.attr).toEqual(sut.attr("domainComponent")));
|
||||
@ -31,8 +31,8 @@ describe("LDAP schema items", () => {
|
||||
});
|
||||
|
||||
describe("Attributes", () => {
|
||||
const sn = sut.attr("sn"),
|
||||
name = sut.attr("name");
|
||||
const sn = sut.attr("sn");
|
||||
const name = sut.attr("name");
|
||||
|
||||
test("SN is found in schema", () => expect(sn).toBeDefined());
|
||||
|
||||
@ -54,8 +54,8 @@ describe("LDAP schema items", () => {
|
||||
});
|
||||
|
||||
describe("ObjectClass inheritance", () => {
|
||||
const top = sut.oc("top"),
|
||||
dnsDomain = sut.oc("dnsDomain");
|
||||
const top = sut.oc("top");
|
||||
const dnsDomain = sut.oc("dnsDomain");
|
||||
|
||||
function superClasses(cls: ObjectClass | undefined): ObjectClass[] {
|
||||
const result = [];
|
||||
|
@ -1,231 +1,291 @@
|
||||
function unique(element: unknown, index: number, array: Array<unknown>): boolean {
|
||||
return array.indexOf(element) == index;
|
||||
function unique(
|
||||
element: unknown,
|
||||
index: number,
|
||||
array: Array<unknown>
|
||||
): boolean {
|
||||
return array.indexOf(element) == index;
|
||||
}
|
||||
|
||||
export function generalizedTime(dt: string): Date {
|
||||
let tz = dt.substring(14);
|
||||
if (tz != 'Z') {
|
||||
tz = tz.substring(0, 3) + ':'
|
||||
+ (tz.length > 3 ? tz.substring(3, 5) : '00');
|
||||
}
|
||||
return new Date(dt.substring(0, 4) + '-'
|
||||
+ dt.substring( 4, 6) + '-'
|
||||
+ dt.substring( 6, 8) + 'T'
|
||||
+ dt.substring( 8, 10) + ':'
|
||||
+ dt.substring(10, 12) + ':'
|
||||
+ dt.substring(12, 14) + tz);
|
||||
let tz = dt.substring(14);
|
||||
if (tz != "Z") {
|
||||
tz =
|
||||
tz.substring(0, 3) +
|
||||
":" +
|
||||
(tz.length > 3 ? tz.substring(3, 5) : "00");
|
||||
}
|
||||
return new Date(
|
||||
dt.substring(0, 4) +
|
||||
"-" +
|
||||
dt.substring(4, 6) +
|
||||
"-" +
|
||||
dt.substring(6, 8) +
|
||||
"T" +
|
||||
dt.substring(8, 10) +
|
||||
":" +
|
||||
dt.substring(10, 12) +
|
||||
":" +
|
||||
dt.substring(12, 14) +
|
||||
tz
|
||||
);
|
||||
}
|
||||
|
||||
let schema: LdapSchema;
|
||||
|
||||
export class RDN {
|
||||
readonly text: string;
|
||||
readonly attrName: string;
|
||||
readonly value: string;
|
||||
readonly text: string;
|
||||
readonly attrName: string;
|
||||
readonly value: string;
|
||||
|
||||
constructor(value: string) {
|
||||
this.text = value;
|
||||
const parts = value.split('=');
|
||||
this.attrName = parts[0].trim();
|
||||
this.value = parts[1].trim();
|
||||
}
|
||||
constructor(value: string) {
|
||||
this.text = value;
|
||||
const parts = value.split("=");
|
||||
this.attrName = parts[0].trim();
|
||||
this.value = parts[1].trim();
|
||||
}
|
||||
|
||||
toString() { return this.text; }
|
||||
toString() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
eq(other: RDN | undefined) {
|
||||
return other !== undefined
|
||||
&& this.attr !== undefined
|
||||
&& this.attr.eq(other.attr)
|
||||
&& this.attr.matcher(this.value, other.value);
|
||||
}
|
||||
eq(other: RDN | undefined) {
|
||||
return (
|
||||
other !== undefined &&
|
||||
this.attr !== undefined &&
|
||||
this.attr.eq(other.attr) &&
|
||||
this.attr.matcher(this.value, other.value)
|
||||
);
|
||||
}
|
||||
|
||||
get attr() {
|
||||
return schema.attr(this.attrName);
|
||||
}
|
||||
get attr() {
|
||||
return schema.attr(this.attrName);
|
||||
}
|
||||
}
|
||||
|
||||
export class DN {
|
||||
readonly text: string;
|
||||
readonly rdn: RDN;
|
||||
readonly parent: DN | undefined;
|
||||
readonly text: string;
|
||||
readonly rdn: RDN;
|
||||
readonly parent: DN | undefined;
|
||||
|
||||
constructor(value: string) {
|
||||
this.text = value;
|
||||
const parts = value.split(',');
|
||||
this.rdn = new RDN(parts[0]);
|
||||
this.parent = parts.length == 1 ? undefined
|
||||
: new DN(value.slice(parts[0].length + 1));
|
||||
}
|
||||
constructor(value: string) {
|
||||
this.text = value;
|
||||
const parts = value.split(",");
|
||||
this.rdn = new RDN(parts[0]);
|
||||
this.parent =
|
||||
parts.length == 1
|
||||
? undefined
|
||||
: new DN(value.slice(parts[0].length + 1));
|
||||
}
|
||||
|
||||
toString() { return this.text; }
|
||||
toString() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
eq(other: DN | undefined) : boolean {
|
||||
if (!other || !this.rdn.eq(other.rdn)) return false;
|
||||
if (!this.parent && !other.parent) return true;
|
||||
return !!this.parent && this.parent.eq(other.parent!);
|
||||
}
|
||||
eq(other: DN | undefined): boolean {
|
||||
if (!other || !this.rdn.eq(other.rdn)) return false;
|
||||
if (!this.parent && !other.parent) return true;
|
||||
return !!this.parent && this.parent.eq(other.parent!);
|
||||
}
|
||||
}
|
||||
|
||||
class Element {
|
||||
readonly oid?: string;
|
||||
readonly name?: string;
|
||||
readonly names?: string[];
|
||||
readonly sup?: string[];
|
||||
readonly oid?: string;
|
||||
readonly name?: string;
|
||||
readonly names?: string[];
|
||||
readonly sup?: string[];
|
||||
}
|
||||
|
||||
export class ObjectClass extends Element {
|
||||
readonly desc?: string;
|
||||
readonly obsolete?: boolean;
|
||||
readonly may?: string[];
|
||||
readonly must?: string[];
|
||||
readonly kind?: string;
|
||||
readonly desc?: string;
|
||||
readonly obsolete?: boolean;
|
||||
readonly may?: string[];
|
||||
readonly must?: string[];
|
||||
readonly kind?: string;
|
||||
|
||||
constructor(json: object) {
|
||||
super();
|
||||
Object.assign(this, json);
|
||||
}
|
||||
|
||||
get structural() { return this.kind == 'structural'; }
|
||||
|
||||
// gather values from a field across all superclasses
|
||||
$collect(name: "must" | "may"): string[] {
|
||||
const attributes = [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
for (let oc: ObjectClass | undefined = this; oc; oc = oc.$super) {
|
||||
const attrs = oc[name];
|
||||
if (attrs) attributes.push(attrs);
|
||||
constructor(json: object) {
|
||||
super();
|
||||
Object.assign(this, json);
|
||||
}
|
||||
|
||||
const result = attributes.flat()
|
||||
.map(attr => schema.attr(attr))
|
||||
.map(obj => obj?.name)
|
||||
.filter(unique) as string[];
|
||||
result.sort();
|
||||
return result;
|
||||
}
|
||||
get structural() {
|
||||
return this.kind == "structural";
|
||||
}
|
||||
|
||||
toString() { return this.name!; }
|
||||
// gather values from a field across all superclasses
|
||||
$collect(name: "must" | "may"): string[] {
|
||||
const attributes = [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
for (let oc: ObjectClass | undefined = this; oc; oc = oc.$super) {
|
||||
const attrs = oc[name];
|
||||
if (attrs) attributes.push(attrs);
|
||||
}
|
||||
|
||||
get $super(): ObjectClass | undefined {
|
||||
const parent = Object.getPrototypeOf(this) as ObjectClass;
|
||||
return parent.sup ? parent : undefined;
|
||||
}
|
||||
const result = attributes
|
||||
.flat()
|
||||
.map((attr) => schema.attr(attr))
|
||||
.map((obj) => obj?.name)
|
||||
.filter(unique) as string[];
|
||||
result.sort();
|
||||
return result;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.name!;
|
||||
}
|
||||
|
||||
get $super(): ObjectClass | undefined {
|
||||
const parent = Object.getPrototypeOf(this) as ObjectClass;
|
||||
return parent.sup ? parent : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const matchRules: {[key: string]: (a: string, b: string) => boolean} = {
|
||||
// See: https://ldap.com/matching-rules/
|
||||
distinguishedNameMatch: (a: string, b: string) => new DN(a).eq(new DN(b)),
|
||||
caseIgnoreIA5Match: (a: string, b: string) => a.toLowerCase() == b.toLowerCase(),
|
||||
caseIgnoreMatch: (a: string, b: string) => a.toLowerCase() == b.toLowerCase(),
|
||||
// generalizedTimeMatch: ...
|
||||
integerMatch: (a: string, b: string) => +a == +b,
|
||||
numericStringMatch: (a: string, b: string) => +a == +b,
|
||||
octetStringMatch: (a: string, b: string) => a == b,
|
||||
const matchRules: { [key: string]: (a: string, b: string) => boolean } = {
|
||||
// See: https://ldap.com/matching-rules/
|
||||
distinguishedNameMatch: (a: string, b: string) => new DN(a).eq(new DN(b)),
|
||||
caseIgnoreIA5Match: (a: string, b: string) =>
|
||||
a.toLowerCase() == b.toLowerCase(),
|
||||
caseIgnoreMatch: (a: string, b: string) =>
|
||||
a.toLowerCase() == b.toLowerCase(),
|
||||
// generalizedTimeMatch: ...
|
||||
integerMatch: (a: string, b: string) => +a == +b,
|
||||
numericStringMatch: (a: string, b: string) => +a == +b,
|
||||
octetStringMatch: (a: string, b: string) => a == b,
|
||||
};
|
||||
|
||||
export class Attribute extends Element {
|
||||
desc?: string;
|
||||
equality?: string; // possibly null in JSON
|
||||
obsolete?: boolean;
|
||||
ordering?: string; // possibly null in JSON
|
||||
no_user_mod?: boolean;
|
||||
single_value?: boolean;
|
||||
substr?: string; // possibly null in JSON
|
||||
syntax?: string; // possibly null in JSON
|
||||
usage?: string;
|
||||
desc?: string;
|
||||
equality?: string; // possibly null in JSON
|
||||
obsolete?: boolean;
|
||||
ordering?: string; // possibly null in JSON
|
||||
no_user_mod?: boolean;
|
||||
single_value?: boolean;
|
||||
substr?: string; // possibly null in JSON
|
||||
syntax?: string; // possibly null in JSON
|
||||
usage?: string;
|
||||
|
||||
constructor(json: object) {
|
||||
super();
|
||||
constructor(json: object) {
|
||||
super();
|
||||
|
||||
// Hack alert: Wipe undefined attributes,
|
||||
// they are looked up via the prototype chain
|
||||
delete this.equality;
|
||||
delete this.ordering;
|
||||
delete this.substr;
|
||||
delete this.syntax;
|
||||
// End of hack
|
||||
// Hack alert: Wipe undefined attributes,
|
||||
// they are looked up via the prototype chain
|
||||
delete this.equality;
|
||||
delete this.ordering;
|
||||
delete this.substr;
|
||||
delete this.syntax;
|
||||
// End of hack
|
||||
|
||||
Object.assign(this, Object.fromEntries(Object.entries(json)
|
||||
.filter(([_prop, value]) => value != null)));
|
||||
}
|
||||
Object.assign(
|
||||
this,
|
||||
Object.fromEntries(
|
||||
Object.entries(json).filter(([_prop, value]) => value != null)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
toString() { return this.name!; }
|
||||
toString() {
|
||||
return this.name!;
|
||||
}
|
||||
|
||||
get matcher() {
|
||||
return (this.equality ? matchRules[this.equality] : undefined)
|
||||
|| matchRules.octetStringMatch;
|
||||
}
|
||||
get matcher() {
|
||||
return (
|
||||
(this.equality ? matchRules[this.equality] : undefined) ||
|
||||
matchRules.octetStringMatch
|
||||
);
|
||||
}
|
||||
|
||||
eq(other: Attribute | undefined) {
|
||||
return other && this.oid == other.oid;
|
||||
}
|
||||
eq(other: Attribute | undefined) {
|
||||
return other && this.oid == other.oid;
|
||||
}
|
||||
|
||||
get binary() {
|
||||
if (this.equality == 'octetStringMatch') return undefined;
|
||||
return this.$syntax?.not_human_readable;
|
||||
}
|
||||
get binary() {
|
||||
if (this.equality == "octetStringMatch") return undefined;
|
||||
return this.$syntax?.not_human_readable;
|
||||
}
|
||||
|
||||
get $syntax() { return schema.syntaxes.get(this.syntax!); }
|
||||
get $syntax() {
|
||||
return schema.syntaxes.get(this.syntax!);
|
||||
}
|
||||
|
||||
get $super() {
|
||||
const parent = Object.getPrototypeOf(this);
|
||||
return parent.sup ? parent : undefined;
|
||||
}
|
||||
get $super() {
|
||||
const parent = Object.getPrototypeOf(this);
|
||||
return parent.sup ? parent : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class Syntax {
|
||||
readonly oid?: string;
|
||||
readonly desc?: string;
|
||||
readonly not_human_readable?: boolean;
|
||||
readonly oid?: string;
|
||||
readonly desc?: string;
|
||||
readonly not_human_readable?: boolean;
|
||||
|
||||
constructor(json: object) {
|
||||
Object.assign(this, json);
|
||||
}
|
||||
constructor(json: object) {
|
||||
Object.assign(this, json);
|
||||
}
|
||||
|
||||
toString() { return this.desc!; }
|
||||
toString() {
|
||||
return this.desc!;
|
||||
}
|
||||
}
|
||||
|
||||
interface JsonSchema {
|
||||
attributes: object;
|
||||
objectClasses: object;
|
||||
syntaxes: object;
|
||||
attributes: object;
|
||||
objectClasses: object;
|
||||
syntaxes: object;
|
||||
}
|
||||
|
||||
export class LdapSchema extends Object {
|
||||
readonly attributes: Array<Attribute>;
|
||||
readonly objectClasses: Map<string, ObjectClass>;
|
||||
readonly syntaxes: Map<string, Syntax>;
|
||||
readonly attributesByName: Map<string, Attribute>;
|
||||
readonly attributes: Array<Attribute>;
|
||||
readonly objectClasses: Map<string, ObjectClass>;
|
||||
readonly syntaxes: Map<string, Syntax>;
|
||||
readonly attributesByName: Map<string, Attribute>;
|
||||
|
||||
constructor(json: JsonSchema) {
|
||||
super();
|
||||
this.syntaxes = new Map(Object.entries(json.syntaxes)
|
||||
.map(([oid, obj]) => [oid, new Syntax(obj)]));
|
||||
this.attributes = Object.values(json.attributes)
|
||||
.map(obj => new Attribute(obj));
|
||||
this.objectClasses = new Map(Object.entries(json.objectClasses)
|
||||
.map(([key, obj]) => [key.toLowerCase(), new ObjectClass(obj)]));
|
||||
this.buildPrototypeChain(this.objectClasses);
|
||||
|
||||
this.attributesByName = new Map(this.attributes.flatMap(
|
||||
attr => (attr.names || []).map(name => [name.toLowerCase(), attr])));
|
||||
this.buildPrototypeChain(this.attributesByName);
|
||||
schema = this as LdapSchema;
|
||||
}
|
||||
constructor(json: JsonSchema) {
|
||||
super();
|
||||
this.syntaxes = new Map(
|
||||
Object.entries(json.syntaxes).map(([oid, obj]) => [
|
||||
oid,
|
||||
new Syntax(obj),
|
||||
])
|
||||
);
|
||||
this.attributes = Object.values(json.attributes).map(
|
||||
(obj) => new Attribute(obj)
|
||||
);
|
||||
this.objectClasses = new Map(
|
||||
Object.entries(json.objectClasses).map(([key, obj]) => [
|
||||
key.toLowerCase(),
|
||||
new ObjectClass(obj),
|
||||
])
|
||||
);
|
||||
this.buildPrototypeChain(this.objectClasses);
|
||||
|
||||
private buildPrototypeChain(elements: Map<string, Element>): void {
|
||||
for (const element of elements.values()) {
|
||||
const key = element.sup ? element.sup[0] : undefined,
|
||||
parent = key ? elements.get(key.toLowerCase()) : undefined;
|
||||
if (parent) Object.setPrototypeOf(element, parent);
|
||||
this.attributesByName = new Map(
|
||||
this.attributes.flatMap((attr) =>
|
||||
(attr.names || []).map((name) => [name.toLowerCase(), attr])
|
||||
)
|
||||
);
|
||||
this.buildPrototypeChain(this.attributesByName);
|
||||
schema = this as LdapSchema;
|
||||
}
|
||||
}
|
||||
|
||||
attr(name: string | undefined) { return this.attributesByName.get(name?.toLowerCase() || ''); }
|
||||
oc(name: string | undefined) { return this.objectClasses.get(name?.toLowerCase() || ''); }
|
||||
private buildPrototypeChain(elements: Map<string, Element>): void {
|
||||
for (const element of elements.values()) {
|
||||
const key = element.sup ? element.sup[0] : undefined;
|
||||
const parent = key ? elements.get(key.toLowerCase()) : undefined;
|
||||
if (parent) Object.setPrototypeOf(element, parent);
|
||||
}
|
||||
}
|
||||
|
||||
search(q: string) {
|
||||
return this.attributes.filter(
|
||||
attr => attr.names?.some(name => name.toLowerCase().startsWith(q.toLowerCase())));
|
||||
}
|
||||
attr(name: string | undefined) {
|
||||
return this.attributesByName.get(name?.toLowerCase() || "");
|
||||
}
|
||||
oc(name: string | undefined) {
|
||||
return this.objectClasses.get(name?.toLowerCase() || "");
|
||||
}
|
||||
|
||||
search(q: string) {
|
||||
return this.attributes.filter((attr) =>
|
||||
attr.names?.some((name) =>
|
||||
name.toLowerCase().startsWith(q.toLowerCase())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -90,16 +90,16 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
title: { type: String, required: true },
|
||||
open: { type: Boolean, required: true },
|
||||
okTitle: { type: String, default: "OK" },
|
||||
okClasses: { type: String, default: "bg-primary/80" },
|
||||
cancelTitle: { type: String, default: "Cancel" },
|
||||
cancelClasses: { type: String, default: "bg-secondary" },
|
||||
hideFooter: { type: Boolean, default: false },
|
||||
returnTo: String,
|
||||
}),
|
||||
emit = defineEmits(["ok", "cancel", "show", "shown", "hide", "hidden"]);
|
||||
title: { type: String, required: true },
|
||||
open: { type: Boolean, required: true },
|
||||
okTitle: { type: String, default: "OK" },
|
||||
okClasses: { type: String, default: "bg-primary/80" },
|
||||
cancelTitle: { type: String, default: "Cancel" },
|
||||
cancelClasses: { type: String, default: "bg-secondary" },
|
||||
hideFooter: { type: Boolean, default: false },
|
||||
returnTo: String,
|
||||
});
|
||||
const emit = defineEmits(["ok", "cancel", "show", "shown", "hide", "hidden"]);
|
||||
|
||||
function onOk() {
|
||||
if (props.open) emit("ok");
|
||||
|
@ -23,11 +23,11 @@
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { useEventListener, useMouseInElement } from "@vueuse/core";
|
||||
|
||||
const props = defineProps({ open: Boolean }),
|
||||
emit = defineEmits(["opened", "closed", "update:open"]),
|
||||
items = ref<HTMLElement | null>(null),
|
||||
selected = ref<number>(),
|
||||
{ isOutside } = useMouseInElement(items);
|
||||
const props = defineProps({ open: Boolean });
|
||||
const emit = defineEmits(["opened", "closed", "update:open"]);
|
||||
const items = ref<HTMLElement | null>(null);
|
||||
const selected = ref<number>();
|
||||
const { isOutside } = useMouseInElement(items);
|
||||
|
||||
function close() {
|
||||
selected.value = undefined;
|
||||
|
@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps(["value"]),
|
||||
emit = defineEmits(["update:value"]),
|
||||
on = computed(() => props.value == "TRUE");
|
||||
const props = defineProps(["value"]);
|
||||
const emit = defineEmits(["update:value"]);
|
||||
const on = computed(() => props.value == "TRUE");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -8,6 +8,6 @@ export interface Entry {
|
||||
// hints: object;
|
||||
isNew?: boolean;
|
||||
required: string[];
|
||||
}
|
||||
};
|
||||
changed?: string[];
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import type { Ref } from "vue";
|
||||
import type { LdapSchema } from "./schema/schema";
|
||||
import type { LdapSchema } from "../components/schema/schema";
|
||||
|
||||
export interface Provided {
|
||||
readonly schema?: LdapSchema;
|
@ -3,4 +3,4 @@ export interface TreeNode {
|
||||
level?: number;
|
||||
hasSubordinates: boolean;
|
||||
structuralObjectClass: string;
|
||||
}
|
||||
}
|
10
src/main.ts
10
src/main.ts
@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import './tailwind.css';
|
||||
import 'font-awesome/css/font-awesome.min.css';
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import "./tailwind.css";
|
||||
import "font-awesome/css/font-awesome.min.css";
|
||||
|
||||
createApp(App).mount('#app');
|
||||
createApp(App).mount("#app");
|
||||
|
52
src/utils.ts
Normal file
52
src/utils.ts
Normal file
@ -0,0 +1,52 @@
|
||||
export async function get<T>(
|
||||
url: string,
|
||||
headers?: Record<string, string>
|
||||
): Promise<T> {
|
||||
return send(url, undefined, "GET", headers);
|
||||
}
|
||||
|
||||
export async function send<Treceived, Tsent = any | undefined>(
|
||||
url: string,
|
||||
data?: Tsent,
|
||||
method: "POST" | "PUT" | "PATCH" | "DELETE" | "GET" = "POST",
|
||||
headers?: Record<string, string>
|
||||
): Promise<Treceived> {
|
||||
if (fetch) {
|
||||
return fetch(url, {
|
||||
method: method,
|
||||
headers: data
|
||||
? {
|
||||
"Content-Type": "application/json",
|
||||
...headers,
|
||||
}
|
||||
: headers,
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
}).then((response) => {
|
||||
if (!response.ok) return Promise.reject(response);
|
||||
return response.json();
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
for (const header in headers ?? {}) {
|
||||
if (
|
||||
!headers ||
|
||||
!Object.prototype.hasOwnProperty.call(headers, header)
|
||||
)
|
||||
continue;
|
||||
const value = headers[header];
|
||||
xhr.setRequestHeader(header, value);
|
||||
}
|
||||
|
||||
xhr.open(method, url, true);
|
||||
xhr.addEventListener("load", function (e) {
|
||||
resolve(JSON.parse(this.response));
|
||||
});
|
||||
xhr.addEventListener("error", function (e) {
|
||||
reject(e);
|
||||
});
|
||||
if (data) xhr.send(JSON.stringify(data));
|
||||
else xhr.send();
|
||||
});
|
||||
}
|
7
src/views/LoginView.vue
Normal file
7
src/views/LoginView.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
console.log("Rawr");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>Rawr!</div>
|
||||
</template>
|
@ -16,7 +16,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
entry: { type: Object, required: true },
|
@ -15,7 +15,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
entry: { type: Object, required: true },
|
@ -19,7 +19,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
dn: { type: String, required: true },
|
@ -22,7 +22,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
entry: { type: Object, required: true },
|
||||
@ -46,9 +46,9 @@ function onOk() {
|
||||
return;
|
||||
}
|
||||
|
||||
const parts = dn.value.split(","),
|
||||
rdnpart = parts[0].split("="),
|
||||
rdn = rdnpart[0];
|
||||
const parts = dn.value.split(",");
|
||||
const rdnpart = parts[0].split("=");
|
||||
const rdn = rdnpart[0];
|
||||
|
||||
if (rdnpart.length != 2) {
|
||||
error.value = "Invalid RDN: " + parts[0];
|
@ -32,9 +32,9 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import NodeLabel from "../NodeLabel.vue";
|
||||
import type { TreeNode } from "../TreeNode";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
import NodeLabel from "@/components/NodeLabel.vue";
|
||||
import type { TreeNode } from "@/data/treeNode";
|
||||
|
||||
const props = defineProps({
|
||||
dn: { type: String, required: true },
|
@ -20,7 +20,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
defineProps({
|
||||
dn: String,
|
@ -18,8 +18,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject, ref } from "vue";
|
||||
import Modal from "./ui/Modal.vue";
|
||||
import type { Provided } from "./Provided";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
const app = inject<Provided>("app");
|
||||
const ldifData = ref("");
|
||||
@ -33,10 +33,10 @@ function init() {
|
||||
|
||||
// Load LDIF from file
|
||||
function upload(evt: Event) {
|
||||
const target = evt.target as HTMLInputElement,
|
||||
files = target.files as FileList,
|
||||
file = files[0],
|
||||
reader = new FileReader();
|
||||
const target = evt.target as HTMLInputElement;
|
||||
const files = target.files as FileList;
|
||||
const file = files[0];
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function () {
|
||||
ldifData.value = reader.result as string;
|
@ -40,9 +40,9 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject, ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import type { Provided } from "../Provided";
|
||||
import type { Entry } from "./Entry";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
import type { Provided } from "@/data/provided";
|
||||
import type { Entry } from "@/data/entry";
|
||||
|
||||
const props = defineProps({
|
||||
dn: { type: String, required: true },
|
@ -48,9 +48,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import { computed, inject, ref } from "vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
import "@/utils";
|
||||
import type { Provided } from "@/data/provided";
|
||||
|
||||
const props = defineProps({
|
||||
entry: { type: Object, required: true },
|
||||
@ -58,12 +59,18 @@ const props = defineProps({
|
||||
returnTo: String,
|
||||
user: String,
|
||||
});
|
||||
|
||||
const app = inject<Provided>("app");
|
||||
|
||||
const oldPassword = ref("");
|
||||
const newPassword = ref("");
|
||||
const repeated = ref("");
|
||||
|
||||
const passwordOk = ref<boolean>();
|
||||
|
||||
const old = ref<HTMLInputElement | null>(null);
|
||||
const changed = ref<HTMLInputElement | null>(null);
|
||||
|
||||
const currentUser = computed(() => props.user == props.entry.meta.dn);
|
||||
const passwordsMatch = computed(
|
||||
() => newPassword.value && newPassword.value == repeated.value
|
||||
@ -97,6 +104,7 @@ async function check() {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ check: oldPassword.value }),
|
||||
headers: {
|
||||
...(app?.authHeaders.value ?? {}),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
@ -19,7 +19,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import Modal from "../ui/Modal.vue";
|
||||
import Modal from "@/components/ui/Modal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
entry: { type: Object, required: true },
|
@ -1,13 +1,15 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.js", "src/**/*.vue"],
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.js", "src/**/*.vue", "src/**/*.ts"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": ["./src/*"],
|
||||
"@views/*": ["./src/views/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import vue from "@vitejs/plugin-vue";
|
||||
export default defineConfig({
|
||||
plugins: [vue(), viteCompression()],
|
||||
|
||||
base: "./",
|
||||
|
||||
build: {
|
||||
manifest: true,
|
||||
chunkSizeWarningLimit: 600,
|
||||
@ -17,6 +15,7 @@ export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
"@views": fileURLToPath(new URL("./src/views", import.meta.url)),
|
||||
},
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user