@logilab/sparqlexplorer 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +73 -0
  3. package/build/src/lib/App.d.ts +6 -0
  4. package/build/src/lib/components/ClassList.d.ts +9 -0
  5. package/build/src/lib/components/EndpointForm.d.ts +1 -0
  6. package/build/src/lib/components/GraphSelector.d.ts +1 -0
  7. package/build/src/lib/components/HomePage.d.ts +1 -0
  8. package/build/src/lib/components/SearchPage.d.ts +1 -0
  9. package/build/src/lib/components/UriPage.d.ts +1 -0
  10. package/build/src/lib/components/UtilsComponents.d.ts +11 -0
  11. package/build/src/lib/components/ViewSelector.d.ts +2 -0
  12. package/build/src/lib/components/Yasgui.d.ts +6 -0
  13. package/build/src/lib/components/YasrTableResults.d.ts +55 -0
  14. package/build/src/lib/components/layout/DrawerContent.d.ts +4 -0
  15. package/build/src/lib/components/layout/Footer.d.ts +1 -0
  16. package/build/src/lib/components/layout/Layout.d.ts +2 -0
  17. package/build/src/lib/components/layout/Navbar.d.ts +4 -0
  18. package/build/src/lib/components/uri/URIDefaultView.d.ts +6 -0
  19. package/build/src/lib/components/uri/URIWithSelectedView.d.ts +7 -0
  20. package/build/src/lib/context/AuthContext.d.ts +11 -0
  21. package/build/src/lib/context/ConfigContext.d.ts +15 -0
  22. package/build/src/lib/context/ViewsContext.d.ts +14 -0
  23. package/build/src/lib/hooks/useClasses.d.ts +6 -0
  24. package/build/src/lib/hooks/useGraphs.d.ts +8 -0
  25. package/build/src/lib/hooks/useNavigateWithParams.d.ts +5 -0
  26. package/build/src/lib/hooks/useParams.d.ts +1 -0
  27. package/build/src/lib/hooks/useURIData.d.ts +21 -0
  28. package/build/src/lib/hooks/useURILink.d.ts +1 -0
  29. package/build/src/lib/index.d.ts +8 -0
  30. package/build/src/lib/public-path.d.ts +1 -0
  31. package/build/src/lib/routes/Home.d.ts +1 -0
  32. package/build/src/lib/routes/Search.d.ts +1 -0
  33. package/build/src/lib/routes/Uri.d.ts +1 -0
  34. package/build/src/lib/routes/Yasgui.d.ts +1 -0
  35. package/build/src/lib/setupTests.d.ts +1 -0
  36. package/build/src/lib/utils/getIconFromURI.d.ts +3 -0
  37. package/build/src/lib/utils/utils.d.ts +24 -0
  38. package/build/src/lib/yasgui-utils/Storage.d.ts +16 -0
  39. package/build/src/lib/yasgui-utils/index.d.ts +16 -0
  40. package/build/static/js/lib.js +285 -0
  41. package/build/static/js/lib.js.LICENSE.txt +71 -0
  42. package/build/static/js/lib.js.map +1 -0
  43. package/package.json +73 -0
  44. package/src/app/index.css +23 -0
  45. package/src/app/index.tsx +28 -0
  46. package/src/app/templates/constants.js +1 -0
  47. package/src/app/templates/index.hbs +18 -0
  48. package/src/lib/App.css +83 -0
  49. package/src/lib/App.tsx +31 -0
  50. package/src/lib/components/ClassList.tsx +173 -0
  51. package/src/lib/components/EndpointForm.tsx +126 -0
  52. package/src/lib/components/GraphSelector.tsx +114 -0
  53. package/src/lib/components/HomePage.tsx +51 -0
  54. package/src/lib/components/SearchPage.tsx +211 -0
  55. package/src/lib/components/UriPage.tsx +158 -0
  56. package/src/lib/components/UtilsComponents.tsx +54 -0
  57. package/src/lib/components/ViewSelector.css +22 -0
  58. package/src/lib/components/ViewSelector.tsx +78 -0
  59. package/src/lib/components/Yasgui.tsx +127 -0
  60. package/src/lib/components/YasrTableResults.ts +529 -0
  61. package/src/lib/components/layout/DrawerContent.tsx +55 -0
  62. package/src/lib/components/layout/Footer.tsx +32 -0
  63. package/src/lib/components/layout/Layout.tsx +103 -0
  64. package/src/lib/components/layout/Navbar.tsx +231 -0
  65. package/src/lib/components/uri/URIDefaultView.tsx +392 -0
  66. package/src/lib/components/uri/URIWithSelectedView.tsx +31 -0
  67. package/src/lib/context/AuthContext.tsx +32 -0
  68. package/src/lib/context/ConfigContext.tsx +50 -0
  69. package/src/lib/context/ViewsContext.tsx +53 -0
  70. package/src/lib/hooks/useClasses.ts +48 -0
  71. package/src/lib/hooks/useGraphs.ts +67 -0
  72. package/src/lib/hooks/useNavigateWithParams.tsx +97 -0
  73. package/src/lib/hooks/useParams.tsx +8 -0
  74. package/src/lib/hooks/useURIData.ts +180 -0
  75. package/src/lib/hooks/useURILink.ts +7 -0
  76. package/src/lib/index.tsx +9 -0
  77. package/src/lib/public-path.ts +3 -0
  78. package/src/lib/routes/Home.tsx +13 -0
  79. package/src/lib/routes/Search.tsx +13 -0
  80. package/src/lib/routes/Uri.tsx +10 -0
  81. package/src/lib/routes/Yasgui.tsx +13 -0
  82. package/src/lib/setupTests.ts +5 -0
  83. package/src/lib/types.d.ts +6 -0
  84. package/src/lib/utils/getIconFromURI.ts +32 -0
  85. package/src/lib/utils/prefixInverted.json +2445 -0
  86. package/src/lib/utils/utils.ts +131 -0
  87. package/src/lib/yasgui-utils/Storage.ts +117 -0
  88. package/src/lib/yasgui-utils/index.ts +66 -0
@@ -0,0 +1,131 @@
1
+ import {
2
+ SPARQL_VIEWS,
3
+ type SparqlViewConfig,
4
+ } from "@logilab/sparqlexplorer-views";
5
+ import type { SparqlAuth } from "@logilab/sparqlutils";
6
+ import prefix from "./prefixInverted.json";
7
+
8
+ export interface RDFNode {
9
+ type: "uri" | "bnode" | "literal";
10
+ value: string;
11
+ }
12
+
13
+ export function stringIncludes(a: string, b: string) {
14
+ return a.toLowerCase().includes(b.toLowerCase());
15
+ }
16
+
17
+ export function computeRedirect(uri: string, params: string) {
18
+ return `/#/browse/${encodeURIComponent(uri)}?${params}`;
19
+ }
20
+
21
+ export function prefixedNameFromUri(uri: string) {
22
+ const prefixCandidates = Object.entries(prefix).filter(([baseUri]) =>
23
+ uri.startsWith(baseUri),
24
+ );
25
+ if (prefixCandidates.length > 0) {
26
+ // take the baseUri with the highest length
27
+ const [bestBaseUri, bestPrefix] = prefixCandidates.sort(
28
+ ([baseUri1], [baseUri2]) => baseUri2.length - baseUri1.length,
29
+ )[0];
30
+ return uri.replace(bestBaseUri, `${bestPrefix}:`);
31
+ }
32
+ return uri;
33
+ }
34
+
35
+ const SAVED_ENDPOINT_KEY = "sparqlexplorer.endpoints";
36
+
37
+ function stringToStringArray(rawValue: string | null): Array<string> {
38
+ if (rawValue !== null) {
39
+ try {
40
+ const arrayValue = JSON.parse(rawValue);
41
+ if (
42
+ Array.isArray(arrayValue) &&
43
+ arrayValue.every((v) => typeof v === "string")
44
+ ) {
45
+ return arrayValue;
46
+ }
47
+ return [];
48
+ } catch {
49
+ return [];
50
+ }
51
+ }
52
+ return [];
53
+ }
54
+
55
+ export function getSavedEndpoints(): Array<string> {
56
+ const rawValue = localStorage.getItem(SAVED_ENDPOINT_KEY);
57
+ return stringToStringArray(rawValue);
58
+ }
59
+
60
+ export function addToSavedEndpoints(value: string) {
61
+ const current = new Set(getSavedEndpoints());
62
+ current.add(value);
63
+ const stringValue = JSON.stringify(Array.from(current));
64
+ localStorage.setItem(SAVED_ENDPOINT_KEY, stringValue);
65
+ }
66
+
67
+ export function getApplicableViews(
68
+ uri: string,
69
+ endpoint: string,
70
+ auth?: SparqlAuth,
71
+ ): Promise<Array<SparqlViewConfig>> {
72
+ return Promise.all(
73
+ SPARQL_VIEWS.map((view) => {
74
+ console.log(view.name);
75
+ return view.isApplicable(uri, endpoint, auth);
76
+ }),
77
+ ).then((viewsApplicablities) => {
78
+ return SPARQL_VIEWS.filter((_view, idx) => viewsApplicablities[idx]);
79
+ });
80
+ }
81
+
82
+ export const DEFAUT_VIEW_NAME = "Default view";
83
+
84
+ export function isDefaultView(viewName: string | null) {
85
+ return viewName === DEFAUT_VIEW_NAME;
86
+ }
87
+
88
+ export function getLabelSparqlClause(
89
+ uri?: string,
90
+ onlyRdfsLabel: boolean = false,
91
+ ) {
92
+ const predicates = onlyRdfsLabel
93
+ ? ["<http://www.w3.org/2000/01/rdf-schema#label>"]
94
+ : [
95
+ "<http://www.w3.org/2000/01/rdf-schema#label>",
96
+ "<http://xmlns.com/foaf/0.1/name>",
97
+ "<http://purl.org/dc/terms/identifier>",
98
+ "<http://www.w3.org/2004/02/skos/core#prefLabel>",
99
+ "<http://www.w3.org/2008/05/skos-xl#prefLabel>/<http://www.w3.org/2008/05/skos-xl#literalForm>",
100
+ "<http://purl.org/dc/elements/1.1/title>",
101
+ "<http://purl.org/dc/terms/title>",
102
+ ];
103
+ const predicateString = predicates.join("|");
104
+ const uriSelector = uri ? `<${uri}>` : "?uri";
105
+ return `OPTIONAL{
106
+ {
107
+ ${uriSelector} ${predicateString} ?label
108
+ }
109
+ }`;
110
+ }
111
+
112
+ export interface Label {
113
+ value: string;
114
+ lang: string | null;
115
+ }
116
+
117
+ export interface UriAndLabels {
118
+ uri: string;
119
+ labels: Label[];
120
+ }
121
+
122
+ export function getBestLabel(instance: UriAndLabels) {
123
+ const filteredLabels = instance.labels
124
+ .filter((label) => label.lang?.includes("fr"))
125
+ .map((label) => label.value);
126
+ const allLabels = instance.labels.map((label) => label.value);
127
+
128
+ return (
129
+ filteredLabels[0] ?? allLabels[0] ?? prefixedNameFromUri(instance.uri)
130
+ );
131
+ }
@@ -0,0 +1,117 @@
1
+ // FIXME this seems shady
2
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
3
+ const store = require("store");
4
+
5
+ export interface ItemWrapper<V = Record<string, unknown>> {
6
+ exp: number;
7
+ val: V;
8
+ namespace: string;
9
+ time: number;
10
+ }
11
+
12
+ interface QuotaExceededError extends Error {
13
+ quotaExceeded?: boolean;
14
+ }
15
+ export default class Storage {
16
+ private namespace: string;
17
+ constructor(namespace: string) {
18
+ this.namespace = namespace;
19
+ }
20
+ public set<V = Record<string, unknown>>(
21
+ key: string | undefined,
22
+ // biome-ignore lint/suspicious/noExplicitAny: any is ok
23
+ val: any,
24
+ expInSeconds: number,
25
+ // biome-ignore lint/suspicious/noExplicitAny: any is ok
26
+ onQuotaExceeded: (e: any) => void,
27
+ ) {
28
+ if (!store.enabled) return; //this is probably in private mode. Don't run, as we might get Js errors
29
+ this.removeExpiredKeys();
30
+ if (key && val !== undefined) {
31
+ //try to store string for dom objects (e.g. XML result). Otherwise, we might get a circular reference error when stringifying this
32
+ if (val.documentElement)
33
+ val = new XMLSerializer().serializeToString(
34
+ val.documentElement,
35
+ );
36
+ try {
37
+ store.set(key, {
38
+ namespace: this.namespace,
39
+ val: val,
40
+ exp: expInSeconds,
41
+ time: Date.now() / 1000,
42
+ } as ItemWrapper<V>);
43
+ } catch (e) {
44
+ if (e instanceof Error) {
45
+ const quotaExceededError = e as QuotaExceededError;
46
+ quotaExceededError.quotaExceeded = isQuotaExceeded(e);
47
+ if (quotaExceededError.quotaExceeded && onQuotaExceeded) {
48
+ onQuotaExceeded(e);
49
+ } else {
50
+ throw quotaExceededError;
51
+ }
52
+ }
53
+ throw e;
54
+ }
55
+ }
56
+ }
57
+ remove(key: string) {
58
+ if (!store.enabled) return; //this is probably in private mode. Don't run, as we might get Js errors
59
+ if (key) store.remove(key);
60
+ }
61
+ removeExpiredKeys() {
62
+ if (!store.enabled) return;
63
+ store.each((value: ItemWrapper, key: string) => {
64
+ if (value?.exp && Date.now() / 1000 - value.time > value.exp) {
65
+ this.remove(key);
66
+ }
67
+ });
68
+ }
69
+ removeAll() {
70
+ if (!store.enabled) return; //this is probably in private mode. Don't run, as we might get Js errors
71
+ }
72
+ removeNamespace() {
73
+ // biome-ignore lint/suspicious/noExplicitAny: any is ok
74
+ store.each((value: ItemWrapper<any>, key: string) => {
75
+ if (value.namespace && value.namespace === this.namespace)
76
+ this.remove(key);
77
+ });
78
+ }
79
+ get<V>(key?: string): V | undefined {
80
+ if (!store.enabled) return; //this is probably in private mode. Don't run, as we might get Js errors
81
+ if (!key) return;
82
+ this.removeExpiredKeys();
83
+ if (key) {
84
+ const info: ItemWrapper<V> = store.get(key);
85
+ if (!info) {
86
+ return;
87
+ }
88
+ return info.val;
89
+ } else {
90
+ return;
91
+ }
92
+ }
93
+ }
94
+
95
+ // biome-ignore lint/suspicious/noExplicitAny: any is ok
96
+ function isQuotaExceeded(e: any) {
97
+ let quotaExceeded = false;
98
+ if (e) {
99
+ if (e.code) {
100
+ switch (e.code) {
101
+ case 22:
102
+ quotaExceeded = true;
103
+ break;
104
+ case 1014:
105
+ // Firefox
106
+ if (e.name === "NS_ERROR_DOM_QUOTA_REACHED") {
107
+ quotaExceeded = true;
108
+ }
109
+ break;
110
+ }
111
+ } else if (e.number === -2147024882) {
112
+ // Internet Explorer 8
113
+ quotaExceeded = true;
114
+ }
115
+ }
116
+ return quotaExceeded;
117
+ }
@@ -0,0 +1,66 @@
1
+ export function drawSvgStringAsElement(svgString: string) {
2
+ if (svgString && svgString.trim().indexOf("<svg") === 0) {
3
+ //no style passed via config. guess own styles
4
+ const parser = new DOMParser();
5
+ const dom = parser.parseFromString(svgString, "text/xml");
6
+ const svg = dom.documentElement;
7
+ svg.setAttribute("aria-hidden", "true");
8
+
9
+ const svgContainer = document.createElement("div");
10
+ svgContainer.className = "svgImg";
11
+ svgContainer.appendChild(svg);
12
+ return svgContainer;
13
+ }
14
+ throw new Error("No svg string given. Cannot draw");
15
+ }
16
+ export interface FaIcon {
17
+ width: number;
18
+ height: number;
19
+ svgPathData: string;
20
+ }
21
+
22
+ /**
23
+ * Draws font fontawesome icon as svg. This is a lot more lightweight then the option that is offered by fontawesome
24
+ * @param faIcon
25
+ * @returns
26
+ */
27
+ export function drawFontAwesomeIconAsSvg(faIcon: FaIcon) {
28
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${faIcon.width} ${faIcon.height}" aria-hidden="true"><path fill="currentColor" d="${faIcon.svgPathData}"></path></svg>`;
29
+ }
30
+
31
+ export function hasClass(el: Element | undefined, className: string) {
32
+ if (!el) return;
33
+ if (el.classList) return el.classList.contains(className);
34
+ else
35
+ return !!el.className.match(
36
+ new RegExp("(\\s|^)" + className + "(\\s|$)"),
37
+ );
38
+ }
39
+
40
+ export function addClass(
41
+ el: Element | undefined | null,
42
+ ...classNames: string[]
43
+ ) {
44
+ if (!el) return;
45
+ for (const className of classNames) {
46
+ if (el.classList) el.classList.add(className);
47
+ else if (!hasClass(el, className)) el.className += " " + className;
48
+ }
49
+ }
50
+
51
+ export function removeClass(el: Element | undefined | null, className: string) {
52
+ if (!el) return;
53
+ if (el.classList) el.classList.remove(className);
54
+ else if (hasClass(el, className)) {
55
+ const reg = new RegExp("(\\s|^)" + className + "(\\s|$)");
56
+ el.className = el.className.replace(reg, " ");
57
+ }
58
+ }
59
+
60
+ export function getAsValue<E, A>(valueOrFn: E | ((arg: A) => E), arg: A): E {
61
+ if (typeof valueOrFn === "function") {
62
+ // biome-ignore lint/suspicious/noExplicitAny: any is ok
63
+ return (valueOrFn as any)(arg);
64
+ }
65
+ return valueOrFn;
66
+ }