At work we have a basic Docusaurus v2 page for user documentation, and I can't share it for privacy reasons. Suffice it to say it has a sidebar which is autogenerated, where the top level contains a number of folders as categories and each category only contains .md files.
At the top level (the level of the categories) there is an empty index.md file that only exists so that the page will load. The autogenerated sidebar includes an index entry that points to a blank page. I would like to hide/get rid of this entry.
I have looked at this github discussion on something similar, but I haven't been able to make the solutions work. The sidebar.js file has the following simple contents:
module.exports = {
docs: [
{
type: 'autogenerated',
dirName: '.'
},
],
};
I have tried adding an exclude: ['path\to\index\file'] line, but this results in the error "exclude" is not allowed.
What is the proper way of hiding this index entry from the sidebar? Alternatively, is there a way to set up the site so that the index.md file is not needed at all?
I have the same setup:
/folder1
/file
/folder2
/file
index
And I wand to autogenerate the sidebar with two categories only:
folder1
folder2
Moreover, I wanted to click on the navbar and see index.
I was able to do so by:
Create a custom sidebar
function skipIndex(items) {
return items.filter(({ type, id }) => {
return type !== 'doc' || id !== 'index';
});
}
module.exports = async function sidebarItemsGenerator({ defaultSidebarItemsGenerator, ...args }) {
const sidebarItems = await defaultSidebarItemsGenerator(args);
return skipIndex(sidebarItems);
}
Then in the docusaurus.config.js
presets: [
[
'classic',
({
// https://docusaurus.io/docs/api/plugins/#docusaurus/plugin-content-docs#configuration
docs: {
sidebarItemsGenerator: require('./sidebar.js'),
},
And finally in the index.md file I must add this metadata, otherwise when I reach the index page, the sidebar disappears because the page is not included:
---
displayed_sidebar: docsSidebar
---
Related
In my TYPO3 9 installation I'am working on a custom sitemap.xml for my own extension (Events). There I want to have a separate pageId / detail page for each entry.
As i understood in the config section of tx_seo I can only provide one specific pageId as detail page id - correct?
I tried this config:
plugin.tx_seo {
config {
xmlSitemap {
sitemaps {
veranstaltung {
provider = TYPO3\CMS\Seo\XmlSitemap\RecordsXmlSitemapDataProvider
config {
table = tx_ntevents_domain_model_veranstaltung
sortField = kursnummer
lastModifiedField = tstamp
recursive = 1
pid = 110
url {
pageId = # here different pages which can be found in tx_ntevents_domain_model_veranstaltung.seite1 #
fieldToParameterMap {
uid = nt_events_pi1[veranstaltung] # is this correct? #
}
additionalGetParameters {
nt_events_pi1.controller = Veranstaltung
nt_events_pi1.action = show
}
}
...
With this setup tx_seo finds all entries but does not
provide a specific page id for each entry and
does not generate the nice slug url
Here is the slug code from config.yaml
NtEvents:
type: Extbase
extension: NtEvents
plugin: Events
routes:
-
routePath: '/{veranstaltung-url}'
_controller: 'Veranstaltung::show'
_arguments:
veranstaltung-url: veranstaltung
defaultController: 'Veranstaltung::list'
aspects:
veranstaltung-url:
type: PersistedAliasMapper
tableName: tx_ntevents_domain_model_veranstaltung
routeFieldName: slug
routeValuePrefix: /
You can create your own DataProvider, in your case it would probably be easiest to copy the original "\TYPO3\CMS\Seo\XmlSitemap\RecordsXmlSitemapDataProvider" into your own extension and rewrite it according to your wishes or adapt it accordingly.
My node.js MySQL query returns a single row wrapped in [RowPacketData] which I can normally access the ID field using results[0].ID.
However, when I store the result in React state (using hooks) it does not work. I can access the result object, but not fields within it.
function MyReactComponent() {
const [dbEntry, setDbEntry] = useState();
useEffect(() => {
const fetchData = async () => {
const result = await queryFunc(`SELECT * FROM table LIMIT 1`);
console.log(result[0]); // <-- Works (shows [RowDataPacket] object)
console.log(result[0].ID); // <-- Works (shows ID)
setDbEntry(result);
};
fetchData();
}, []);
console.log(dbEntry[0]); // <-- Works (shows [RowDataPacket] object)
console.log(dbEntry[0].ID); // <-- TypeError: Cannot read property '0' of undefined
return (
<p>
{dbEntry[0].ID} // <-- How do I render here?
</p>
)
}
What's going on here? I have a feeling React is coercing the result object somehow, but I can't figure it out...
When you need to display data that comes from an async font(API calls for example), it's possible (actually almost certain) that it won't be available by the time the first render occurs, to solve that there is actually a few things you could do:
Placeholder state
You could have a model of what the data will look like described as your initial state, so properties won't be undefined anymore:
const [state, setState] = useState({
data:[
{name: ''}
]
})
Assuming that your data will have this format accessing state.data[0].name won't throw an error. This could be useful in some cases but I personally don't like the approach.
Conditional Render
At each render you should check for a condition and only if satisfied render the piece of code:
return(
<>
<div>Title</div>
{Boolean(state.data.length) && <div>{state.data[0].name}</div>}
</>
)
Suspense
That one is brand new, if you have a component tha't need to perform side effects before render it's content, you should have a fallback content to be displayed while the async action is being perform.
<Suspense fallback={<span>Loading</span>}>
<MYAsyncComponent />
</Suspense>
I am trying to create a combo box with a list of countries in SAP UI5.
I have created a combo box and have created dynamic list of some countries, but to create more than 100 countries, the only easy way is to create a JSON file of countries and then populate in Controller.js.
I tried to create a JSON file but I am unsure whether I have to store it under model folder or root.
What changes do I have to make in my XML view and controller, and where should I attach countries.json file?
You are looking at something called as "Aggregation Binding" Aggregation Binding in XML views
Here is an example to refer to which explains
How to create a model using data from json file
How to Bind model data to the XML view control(you have to bind comboBox instead of table)
How to bind json data model to an XML view
Let me know if this helps.
Maybe you don't need to create the countries.json file at all :)
As UI5 leverages Common Locale Data Repository (CLDR) internally and provides the data via sap.ui.core.LocaleDataAPI, which includes language names, country names, currency names, singular/plural modifications, and more..
A list of supported regions for the locale data are stored in a JSON format here. In one of those files, if you look at the property "territories", you'll see that the country names are listed among them. You can filter every irrelevant territory out that is not considered a country, and then bind the rest in the items aggregation of the combo box.
Demo
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/Locale",
"sap/ui/core/LocaleData",
"sap/ui/model/json/JSONModel",
"sap/ui/core/mvc/XMLView",
], function(Locale, LocaleData, JSONModel, XMLView) {
"use strict";
XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core" xmlns="sap.m"
height="100%"
displayBlock="true">
<ComboBox class="sapUiTinyMargin"
width="15rem"
placeholder="Select a country.."
filterSecondaryValues="true"
showSecondaryValues="true"
items="{
path: '/',
templateShareable: false,
key: 'code',
sorter: { path: 'name' }
}">
<core:ListItem xmlns:core="sap.ui.core"
key="{code}"
text="{name}"
additionalText="{code}" />
</ComboBox>
</mvc:View>`,
models: createCountryModel(getCountries()),
}).then(view => view.placeAt("content"));
function createCountryModel(countries, sizeLimit = 300) {
const model = new JSONModel(countries);
model.setSizeLimit(sizeLimit);
model.setDefaultBindingMode("OneWay");
return model;
}
function getCountries() {
const territories = getTerritories();
return extractCountriesFrom(territories, byCustomCheck());
}
function getTerritories(localeId) {
const currentConfig = sap.ui.getCore().getConfiguration();
const locale = localeId ? new Locale(localeId) : currentConfig.getLocale();
const localeData = new LocaleData(locale);
return localeData.getTerritories(); // includes country names
}
function extractCountriesFrom(territories, customCheck = () => true) {
const isValidCountry = createCountryCheck(customCheck);
const toObject = code => Object.freeze({
code: code,
name: territories[code],
});
const countryObjects = Object.keys(territories)
.filter(isValidCountry)
.map(toObject);
return Object.freeze(countryObjects);
}
function createCountryCheck(customCheck, obviouslyNotCountries = [
"EU", // "European Union"
"EZ", // "Eurozone"
"UN", // "United Nations"
"ZZ", // "Unknown Region"
]) {
return territoryCode => territoryCode.length == 2
&& !obviouslyNotCountries.includes(territoryCode)
&& customCheck(territoryCode);
}
function byCustomCheck() { // returns a function that returns boolean
// E.g.: list of sanctioned countries you want to exclude
const list = [
"AF",
"KP",
"IR",
// ...
];
return countryCode => !list.includes(countryCode);
}
}));
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core, sap.m"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-async="true"
data-sap-ui-compatversion="edge"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
As you can see in the example, the ComboBox is successfully populated with the countries. When a new LocaleData instance is created, a request is sent immediately (currently via sync XHR) to get the data which are translated in the language that UI5 detects from the client settings. If no language could be detected, the en.json file will be retrieved.src
The above approach has the following advantages:
No need to create and maintain a separate "country" list. ✔️
Multilingual support ✔️
Reusability ✔️ - When UI5 tries to fetch the same locale data file, which is the case when e.g. a Calendar is used, the browser can serve the file quickly from the cache since the same file was already fetched before.
Note
When creating a JSONModel to store more than 100 country names, keep in mind to increase the size limit as well. The current default limit is 100.
I have a query I'm trying to perform based on a one to many relationship.
As an example there is a model called Users and one called Projects.
Users hasMany Projects
Projects have many types which are stored in a type (enum) column. There are 4 different types that potentially a user may have that I want to load. The catch is I want to include the most recent project record (createdAt column) for all networks that potentially will be there. I have not found a way to structure the query for it to work as an include. I have however found a way to do a raw query which does what I want.
I am looking for a way without having to do a raw query. By doing the raw query I have to map the returned results to users I've returned from the other method, or I have to do a simple include and then trim off all the results that are not the most recent. The latter is fine, but I see this getting slower as a user will have many projects and it will keep growing steadily.
This allow serialize a json for anywhere action about a model. Read it, very well
sequelize-virtual-fields
// define models
var Person = sequelize.define('Person', { name: Sequelize.STRING });
var Task = sequelize.define('Task', {
name: Sequelize.STRING,
nameWithPerson: {
type: Sequelize.VIRTUAL,
get: function() { return this.name + ' (' + this.Person.name + ')' }
attributes: [ 'name' ],
include: [ { model: Person, attributes: [ 'name' ] } ],
order: [ ['name'], [ Person, 'name' ] ]
}
});
// define associations
Task.belongsTo(Person);
Person.hasMany(Task);
// activate virtual fields functionality
sequelize.initVirtualFields();
Please share your experience with partial updating of JSON document.At now I'm storing my JSON documents in MongoDB which looks like the following:
{
id: ObjectId(507f191e810c19729de860ea),
title: 'Sterling Archer',
comments: [
{text: 'Comment text', tags: ['tag1', 'tag2', 'tag3']},
{text: 'Comment test', tags: ['tag2', 'tag5']}
]
}
I need to frequently update my documents by using rfc6902 specification. Now, I do it not optimized way that looks the following (I use nodejs/express/mongoose and fast-json-patch module in this example):
var jsonpatch = require('fast-json-patch');
app.patch('/document/:id', function (req, res, next) {
var document_id = req.params.id;
// req.body.patch: { "op": "add", "path": "/comments/2", "value": {text: 'Comment test3', tags: ['tag4']}" }
var patches = req.body.patch;
// find document
Document.findById(document_id, function (err, document) {
// Applying patches
jsonpatch.apply(document, patches);
// Update whole document in MongoDB
Document.update({_id: document_id}, document, function (err) {
return res.status(200).send();
});
});
});
This is not optimize approach to patch documents due two queries in MongoDB and replacing whole document. So I'm looking for optimized approach and want to try RethinkDB for this task. Can you help me to inspect possibility of atomic document updating by using single query with RethinkDB? Or should I looks for another way of resolving my problem?
Please share your experience with partial updating of JSON document.
You just need one query in RethinkDB. Suppose you want to update the document whose id is 1 with the values {foo: 1, bar: 2}, and increment the field "count", you would do
r.table("data").get(1).update(function(doc) {
return doc.merge({foo: 1, bar:2, count: doc("count").add(1) })
})
While this update requires a unique query, the whole document will be updated.
If you have big documents, you can split them in multiple tables and perform joins later to retrieve the data.
You may be interested in reading this article about data modeling: http://www.rethinkdb.com/docs/data-modeling/