searching components
This commit is contained in:
parent
55bf142a95
commit
1413ee6f2c
|
@ -0,0 +1,18 @@
|
|||
|
||||
const apiCall = (method) => (url, body, returnResponse=false) =>
|
||||
fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: body && JSON.stringify(body),
|
||||
}).then(r => returnResponse ? r : r.json());
|
||||
|
||||
const post = apiCall("POST");
|
||||
const get = apiCall("GET");
|
||||
const patch = apiCall("PATCH");
|
||||
const del = apiCall("DELETE");
|
||||
|
||||
export default {
|
||||
post, get, patch, delete:del
|
||||
};
|
|
@ -1,12 +1,31 @@
|
|||
import {hierarchy as hierarchyFunctions,
|
||||
common, getTemplateApi } from "budibase-core";
|
||||
import {filter, cloneDeep, sortBy, map, last, keys,
|
||||
cloneDeep, keyBy,
|
||||
find, isEmpty, groupBy, reduce} from "lodash/fp";
|
||||
import {chain, getNode, validate,
|
||||
constructHierarchy, templateApi} from "../common/core";
|
||||
import {
|
||||
hierarchy as hierarchyFunctions,
|
||||
common
|
||||
} from "budibase-core";
|
||||
import {
|
||||
filter,
|
||||
cloneDeep,
|
||||
sortBy,
|
||||
map,
|
||||
last,
|
||||
keys,
|
||||
cloneDeep,
|
||||
concat,
|
||||
find,
|
||||
isEmpty,
|
||||
groupBy,
|
||||
reduce
|
||||
} from "lodash/fp";
|
||||
import {
|
||||
chain,
|
||||
getNode,
|
||||
validate,
|
||||
constructHierarchy,
|
||||
templateApi
|
||||
} from "../common/core";
|
||||
import {writable} from "svelte/store";
|
||||
import { defaultPagesObject } from "../userInterface/pagesParsing/defaultPagesObject"
|
||||
import api from "./api";
|
||||
|
||||
const pipe = common.$;
|
||||
|
||||
|
@ -53,6 +72,8 @@ export const getStore = () => {
|
|||
store.saveDerivedComponent = saveDerivedComponent(store);
|
||||
store.refreshComponents = refreshComponents(store);
|
||||
store.addComponentLibrary = addComponentLibrary(store);
|
||||
store.renameDerivedComponent = renameDerivedComponent(store);
|
||||
store.deleteDerivedComponent = deleteDerivedComponent(store);
|
||||
return store;
|
||||
}
|
||||
|
||||
|
@ -65,20 +86,20 @@ const initialise = (store, initial) => async () => {
|
|||
: "";
|
||||
|
||||
if(!appname) {
|
||||
initial.apps = await fetch(`/_builder/api/apps`)
|
||||
.then(r => r.json());
|
||||
initial.apps = await api.get(`/_builder/api/apps`);
|
||||
initial.hasAppPackage = false;
|
||||
store.set(initial);
|
||||
return initial;
|
||||
}
|
||||
|
||||
const pkg = await fetch(`/_builder/api/${appname}/appPackage`)
|
||||
.then(r => r.json());
|
||||
const pkg = await api.get(`/_builder/api/${appname}/appPackage`);
|
||||
|
||||
initial.appname = appname;
|
||||
initial.hasAppPackage = true;
|
||||
initial.hierarchy = pkg.appDefinition.hierarchy;
|
||||
initial.accessLevels = pkg.accessLevels;
|
||||
initial.derivedComponents = pkg.derivedComponents;
|
||||
initial.rootComponents = pkg.rootComponents;
|
||||
initial.actions = reduce((arr, action) => {
|
||||
arr.push(action);
|
||||
return arr;
|
||||
|
@ -344,23 +365,53 @@ const saveDerivedComponent = store => (derivedComponent) => {
|
|||
|
||||
s.derivedComponents = derivedComponents;
|
||||
|
||||
fetch(`/_builder/api/${s.appname}/derivedcomponent`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(derivedComponent),
|
||||
});
|
||||
api.post(`/_builder/api/${s.appname}/derivedcomponent`, derivedComponent);
|
||||
|
||||
return s;
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
const deleteDerivedComponent = store => name => {
|
||||
store.update(s => {
|
||||
|
||||
const derivedComponents = pipe(s.derivedComponents, [
|
||||
filter(c => c._name !== name)
|
||||
]);
|
||||
|
||||
s.derivedComponents = derivedComponents;
|
||||
|
||||
api.delete(`/_builder/api/${s.appname}/derivedcomponent/${name}`);
|
||||
|
||||
return s;
|
||||
})
|
||||
}
|
||||
|
||||
const renameDerivedComponent = store => (oldname, newname) => {
|
||||
store.update(s => {
|
||||
|
||||
const component = pipe(s.derivedComponents, [
|
||||
find(c => c._name === name)
|
||||
]);
|
||||
|
||||
component._name = newname;
|
||||
|
||||
const derivedComponents = pipe(s.derivedComponents, [
|
||||
filter(c => c._name !== name),
|
||||
concat(component)
|
||||
]);
|
||||
|
||||
s.derivedComponent = derivedComponents;
|
||||
|
||||
api.delete(`/_builder/api/${s.appname}/derivedcomponent/${name}`);
|
||||
|
||||
return s;
|
||||
})
|
||||
}
|
||||
|
||||
const addComponentLibrary = store => async lib => {
|
||||
|
||||
const response =
|
||||
await fetch(`/_builder/api/${db.appname}/components?${encodeURI(lib)}`);
|
||||
await api.get(`/_builder/api/${db.appname}/components?${encodeURI(lib)}`,undefined, true);
|
||||
|
||||
const success = response.status === 200;
|
||||
|
||||
|
@ -390,8 +441,7 @@ const addComponentLibrary = store => async lib => {
|
|||
const refreshComponents = store => async () => {
|
||||
|
||||
const components =
|
||||
await fetch(`/_builder/api/${db.appname}/components`)
|
||||
.then(r => jQuery.json());
|
||||
await api.get(`/_builder/api/${db.appname}/components`);
|
||||
|
||||
const rootComponents = pipe(components, [
|
||||
keys,
|
||||
|
@ -420,11 +470,5 @@ const savePackage = (store, s) => {
|
|||
accessLevels:s.accessLevels
|
||||
}
|
||||
|
||||
fetch(`/_builder/api/${s.appname}/appPackage`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
api.post(`/_builder/api/${s.appname}/appPackage`, data);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import {
|
||||
find,
|
||||
isUndefined,
|
||||
filter,
|
||||
some,
|
||||
includes
|
||||
} from "lodash/fp";
|
||||
|
||||
import {
|
||||
common
|
||||
} from "budibase-core";
|
||||
|
||||
|
||||
const pipe = common.$;
|
||||
|
||||
const normalString = s => (s||"").trim().toLowerCase();
|
||||
|
||||
const isRootComponent = c => isUndefined(c.inherits);
|
||||
|
||||
export const searchAllComponents = (derivedComponents, rootComponents, phrase) => {
|
||||
|
||||
const hasPhrase = (...vals) => pipe(vals, [
|
||||
some(v => includes(phrase)(v))
|
||||
]);
|
||||
|
||||
const rootComponentMatches = c =>
|
||||
hasPhrase(c.name, ...(c.tags || []));
|
||||
|
||||
const derivedComponentMatches = c => {
|
||||
if(hasPhrase(c.name, ...(c.tags || []))) return true;
|
||||
|
||||
const parent = getExactComponent(
|
||||
derivedComponents,
|
||||
rootComponents,
|
||||
c.inherits);
|
||||
|
||||
if(isRootComponent(parent))
|
||||
return rootComponentMatches(parent);
|
||||
|
||||
return derivedComponentMatches(parent);
|
||||
}
|
||||
|
||||
return ([
|
||||
...filter(derivedComponentMatches)(derivedComponents),
|
||||
...filter(rootComponentMatches)(rootComponents)
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
export const getExactComponent = (derivedComponents, rootComponents, name) => {
|
||||
|
||||
const stringEquals = (s1, s2) =>
|
||||
normalString(s1) === normalString(s2);
|
||||
|
||||
const derived = pipe(derivedComponents,[
|
||||
find(c => stringEquals(c.name, name))
|
||||
]);
|
||||
|
||||
if(derived) return derived;
|
||||
|
||||
const root = pipe(rootComponents,[
|
||||
find(c => stringEquals(c.name, name))
|
||||
]);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
export const getAncestorProps = (derivedComponents, rootComponents, name, found=[]) => {
|
||||
const thisComponent = getExactComponent(
|
||||
derivedComponents, rootComponents, name);
|
||||
|
||||
if(isRootComponent(thisComponent))
|
||||
return [thisComponent.props, ...found];
|
||||
|
||||
return getAncestorProps(
|
||||
derivedComponents,
|
||||
rootComponents,
|
||||
thisComponent.inherits,
|
||||
[{_component:thisComponent.inherits, ...thisComponent.props},
|
||||
...found]);
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
import {
|
||||
searchAllComponents,
|
||||
getExactComponent,
|
||||
getAncestorProps
|
||||
} from "../src/userInterface/pagesParsing/searchComponents";
|
||||
|
||||
|
||||
describe("searchAllComponents", () => {
|
||||
|
||||
it("should match derived component by name", () => {
|
||||
|
||||
const results = searchAllComponents(
|
||||
derivedComponents(),
|
||||
rootComponents(),
|
||||
"smalltextbox"
|
||||
);
|
||||
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].name).toBe("common/SmallTextbox");
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
describe("getExactComponent", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("getAncestorProps", () => {
|
||||
|
||||
})
|
||||
|
||||
const derivedComponents = () => ([
|
||||
{
|
||||
inherits:"budibase-components/TextBox",
|
||||
name: "common/SmallTextbox",
|
||||
props: {
|
||||
size: "small"
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"common/SmallTextbox",
|
||||
name: "common/PasswordBox",
|
||||
tags: ["mask"],
|
||||
props: {
|
||||
isPassword: true
|
||||
}
|
||||
},
|
||||
{
|
||||
inherits:"budibase-components/Button",
|
||||
name:"PrimaryButton",
|
||||
props: {
|
||||
css:"btn-primary"
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const rootComponents = () => ([
|
||||
{
|
||||
name: "budibase-components/TextBox",
|
||||
tags: ["Text", "input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
isPassword: "boolean",
|
||||
placeholder: "string",
|
||||
label:"string"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "budibase-components/Button",
|
||||
tags: ["input"],
|
||||
props: {
|
||||
size: {type:"options", options:["small", "medium", "large"]},
|
||||
css: "string",
|
||||
content: "component"
|
||||
}
|
||||
}
|
||||
])
|
|
@ -1,4 +1,9 @@
|
|||
{
|
||||
"_component": "./customComponents/textbox",
|
||||
"inherits": "./customComponents/textbox",
|
||||
"name": "myTextBox",
|
||||
"tags": [],
|
||||
"description": "A text input, with a label",
|
||||
"props" : {
|
||||
"label": "hello"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
{
|
||||
"_component": "./moreCustomComponents/textbox",
|
||||
"inherits": "./moreCustomComponents/textbox",
|
||||
"name":"subfolder/otherTextBox.json",
|
||||
"tags": [],
|
||||
"description": "A text input, with a label",
|
||||
"props" : {
|
||||
"label": "hello"
|
||||
}
|
||||
}
|
|
@ -68,8 +68,8 @@ it("/apppackage should get derivedComponents", async () => {
|
|||
.expect(statusCodes.OK);
|
||||
|
||||
const expectedComponents = {
|
||||
"myTextBox" : {...derivedComponent1, _name:"myTextBox"},
|
||||
"subfolder/otherTextBox": {...derivedComponent2, _name:"subfolder/otherTextBox"}
|
||||
"myTextBox" : {...derivedComponent1, name:"myTextBox"},
|
||||
"subfolder/otherTextBox": {...derivedComponent2, name:"subfolder/otherTextBox"}
|
||||
};
|
||||
|
||||
expect(body.derivedComponents).toEqual(expectedComponents);
|
||||
|
@ -77,9 +77,11 @@ it("/apppackage should get derivedComponents", async () => {
|
|||
|
||||
it("should be able to create new derived component", async () => {
|
||||
const newDerivedComponent = {
|
||||
_name: "newTextBox",
|
||||
_component: "./customComponents/textbox",
|
||||
name: "newTextBox",
|
||||
inherits: "./customComponents/textbox",
|
||||
props: {
|
||||
label: "something"
|
||||
}
|
||||
};
|
||||
|
||||
await app.post("/_builder/api/testApp/derivedcomponent", newDerivedComponent)
|
||||
|
@ -93,9 +95,11 @@ it("should be able to create new derived component", async () => {
|
|||
|
||||
it("should be able to update derived component", async () => {
|
||||
const updatedDerivedComponent = {
|
||||
_name: "newTextBox",
|
||||
_component: "./customComponents/textbox",
|
||||
name: "newTextBox",
|
||||
inherits: "./customComponents/textbox",
|
||||
props: {
|
||||
label: "something else"
|
||||
}
|
||||
};
|
||||
|
||||
await app.post("/_builder/api/testApp/derivedcomponent", updatedDerivedComponent)
|
||||
|
|
|
@ -41,7 +41,7 @@ module.exports.getPackageForBuilder = async (config, appname) => {
|
|||
|
||||
rootComponents: await getRootComponents(appPath, pages),
|
||||
|
||||
derivedComponents: keyBy("_name")(
|
||||
derivedComponents: keyBy("name")(
|
||||
await fetchDerivedComponents(appPath))
|
||||
})
|
||||
|
||||
|
@ -73,7 +73,7 @@ module.exports.saveDerivedComponent = async (config, appname, component) => {
|
|||
const appPath = appPackageFolder(config, appname);
|
||||
|
||||
await writeJSON(
|
||||
componentPath(appPath, component._name),
|
||||
componentPath(appPath, component.name),
|
||||
component,
|
||||
{encoding:"utf8", flag:"w"});
|
||||
}
|
||||
|
@ -177,7 +177,7 @@ const fetchDerivedComponents = async (appPath, relativePath = "") => {
|
|||
const component =
|
||||
await readJSON(itemFullPath);
|
||||
|
||||
component._name = itemRelativePath
|
||||
component.name = itemRelativePath
|
||||
.substring(0, itemRelativePath.length - 5)
|
||||
.replace(/\\/g, "/");
|
||||
|
||||
|
|
Loading…
Reference in New Issue