Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .docs/images/navigation.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .docs/images/plugin-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"endOfLine": "lf",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}
21 changes: 18 additions & 3 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
[[_TOC_]]

# Plain JS Plugin
# Singleton types

## Usage

Select content types that should only contain one record.

![](.docs/images/plugin-config.png)

Now when you click on the types selected in the plugin configuration you will be taken directly to the edit or add page
of Content object

![](.docs/images/navigation.png)

> **Warning**: Using the plugin does not change the way the API manages objects

## Quick start

Expand All @@ -26,7 +39,9 @@ The plugins are built into a single `dist/index.js` file. The manifest is copied

## Loading the plugin

**Warning:** While developing, you can use `https://localhost:3053/plugin-manifest.json` address to load the plugin manifest. Make sure your browser trusts the local certificate on the latter, to be able to use it e.g. with `https://editor.flotiq.com`
**Warning:** While developing, you can use `https://localhost:3053/plugin-manifest.json` address to load the plugin
manifest. Make sure your browser trusts the local certificate on the latter, to be able to use it e.g.
with `https://editor.flotiq.com`

### URL

Expand All @@ -44,7 +59,7 @@ The plugins are built into a single `dist/index.js` file. The manifest is copied

1. Open Flotiq editor
2. Open Chrome Dev console
3. Paste the content of `dist/index.js`
3. Paste the content of `dist/index.js`
4. Navigate to the view that is modified by the plugin

### Deployment
Expand Down
17 changes: 0 additions & 17 deletions common/api-helpers.js

This file was deleted.

17 changes: 15 additions & 2 deletions common/plugin-element-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,26 @@ export const addElementToCache = (element, key, data = {}) => {
data,
};

let detachTimeoutId;

element.addEventListener('flotiq.attached', () => {
if (detachTimeoutId) {
clearTimeout(detachTimeoutId);
detachTimeoutId = null;
}
});

element.addEventListener('flotiq.detached', () => {
setTimeout(() => {
return delete appRoots[key];
detachTimeoutId = setTimeout(() => {
delete appRoots[key];
}, 50);
});
};

export const addObjectToCache = (key, data = {}) => {
appRoots[key] = data;
};

export const getCachedElement = (key) => {
return appRoots[key];
};
Expand Down
24 changes: 24 additions & 0 deletions i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import i18n from 'i18next';

i18n.init({
fallbackLng: 'en',
supportedLngs: ['en', 'pl'],
resources: {
en: {
translation: {
SingletonTypes: 'Singleton Types',
SingletonTypesDescription:
'List of content types that should only contain one record',
},
},
pl: {
translation: {
SingletonTypes: 'Typy singletonowe',
SingletonTypesDescription:
'Lista typów treści, które powinny zawierać tylko jeden rekord.',
},
},
},
});

export default i18n;
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
},
"dependencies": {
"chalk": "^5.3.0",
"esbuild-plugin-copy": "^2.1.1"
"esbuild-plugin-copy": "^2.1.1",
"i18n": "^0.15.1",
"i18next": "^24.2.0"
}
}
18 changes: 6 additions & 12 deletions plugin-manifest.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
{
"id": "flotiq.plain-js-template",
"name": "Plain JS Plugin Template",
"description": "A plain js example of Flotiq plugin. This plugin changes the rendering of some data in the grid. It renders colorful text properties, bold numbers, and relations as text.",
"version": "0.1.2",
"repository": "https://github.com/flotiq/flotiq-ui-plugin-templates-plain-js",
"id": "flotiq.singleton-types",
"name": "Flotiq singleton types plugin",
"description": "The plugin allows setting selected content types as singletons, redirecting object views to creation or editing skipping the content objects grid",
"version": "0.1.3",
"repository": "https://github.com/flotiq/flotiq-ui-plugin-singleton-types",
"url": "https://localhost:3053/index.js",
"permissions": [
{
"ctdName": "*",
"canRead": true,
"type": "CO"
}
]
"permissions": []
}
62 changes: 0 additions & 62 deletions plugins/grid-renderers/index.js

This file was deleted.

56 changes: 38 additions & 18 deletions plugins/index.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
import { registerFn } from "../common/plugin-element-cache";
import pluginInfo from "../plugin-manifest.json";
import cssString from "inline:./styles/style.css";
import { handleGridPlugin } from "./grid-renderers";
import { registerFn } from '../common/plugin-element-cache';
import pluginInfo from '../plugin-manifest.json';
import cssString from 'inline:./styles/style.css';
import { pluginsManageFormSchemaHandler } from './mange/index.js';
import gridRenderHandler from './navigate/index.js';
import i18n from '../i18n.js';

registerFn(pluginInfo, (handler, client) => {
/**
* Add plugin styles to the head of the document
*/
if (!document.getElementById(`${pluginInfo.id}-styles`)) {
const style = document.createElement("style");
style.id = `${pluginInfo.id}-styles`;
style.textContent = cssString;
document.head.appendChild(style);
}
registerFn(
pluginInfo,
(handler, _, { getPluginSettings, getLanguage, navigate }) => {
/**
* Add plugin styles to the head of the document
*/
if (!document.getElementById(`${pluginInfo.id}-styles`)) {
const style = document.createElement('style');
style.id = `${pluginInfo.id}-styles`;
style.textContent = cssString;
document.head.appendChild(style);
}

handler.on("flotiq.grid.cell::render", (data) =>
handleGridPlugin(data, client, pluginInfo),
);
});
const language = getLanguage();
if (language !== i18n.language) {
i18n.changeLanguage(language);
}

handler.on('flotiq.grid::render', (event) => {
return gridRenderHandler(event, getPluginSettings, navigate);
});

handler.on('flotiq.plugins.manage::form-schema', ({ contentTypes }) => {
return pluginsManageFormSchemaHandler(contentTypes);
});

handler.on('flotiq.language::changed', ({ language }) => {
if (language !== i18n.language) {
i18n.changeLanguage(language);
}
});
},
);
52 changes: 52 additions & 0 deletions plugins/mange/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pluginInfo from '../../plugin-manifest.json';
import i18n from 'i18next';

const getFields = (contentTypes) => {
return {
metaDefinition: {
order: ['singleton_types'],
propertiesConfig: {
singleton_types: {
label: i18n.t('SingletonTypes'),
helpText: i18n.t('SingletonTypesDescription'),
unique: false,
inputType: 'select',
optionsWithLabels: contentTypes,
useOptionsWithLabels: true,
isMultiple: true,
},
},
},
schemaDefinition: {
additionalProperties: false,
required: [],
type: 'object',
allOf: [
{
$ref: '#/components/schemas/AbstractContentTypeSchemaDefinition',
},
{
type: 'object',
properties: {
singleton_types: {
type: 'array',
},
},
},
],
},
};
};

export const pluginsManageFormSchemaHandler = (contentTypes) => {
const ctds = contentTypes
?.filter(({ internal }) => !internal)
?.map(({ name, label }) => ({ value: name, label }));

return {
schema: {
...getFields(ctds),
id: pluginInfo.id,
},
};
};
47 changes: 47 additions & 0 deletions plugins/navigate/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
addElementToCache,
getCachedElement,
} from '../../common/plugin-element-cache.js';

const generateLoader = (pluginId) => {
let loader = getCachedElement(
`${pluginId}-flotiq-singleton-plugin-loader`,
)?.element;

if (!loader) {
loader = document.createElement('div');
loader.classList.add('flotiq-singleton-plugin-loader-container');
loader.innerHTML = '<div class="flotiq-singleton-plugin-loader"></div>';

addElementToCache(loader, `${pluginId}-flotiq-singleton-plugin-loader`);
}

return loader;
};

export default function gridRenderHandler(
{ contentType, contentObjects, isFetching, isLoading },
getPluginSettings,
navigate,
) {
if (isLoading || isFetching) return generateLoader();
const settings = JSON.parse(getPluginSettings());

if (!settings.singleton_types.includes(contentType?.name)) return;

const url = new URL(window.location.href);

if (!contentObjects[0]) {
url.pathname = url.pathname.replace(
'/' + contentType.name,
`/add/${contentType.name}`,
);
} else {
url.pathname = url.pathname.replace(
'/' + contentType.name,
`/edit/${contentType.name}/${contentObjects[0].id}`,
);
}

navigate(url.pathname);
}
Binary file removed plugins/styles/RobotoMono-Medium.ttf
Binary file not shown.
18 changes: 13 additions & 5 deletions plugins/styles/style.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
@font-face {
font-family: "Roboto Mono";
src: url(./RobotoMono-Medium.ttf) format("truetype");
.flotiq-singleton-plugin-loader-container{
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}

.plugin-name-cell-renderer {
font-family: "Roboto Mono", monospace;
.flotiq-singleton-plugin-loader{
width: 50px;
height: 50px;
border: 5px solid #ccc;
border-top: 5px solid #0083FC;
border-radius: 50%;
animation: spin 1s linear infinite;
}
Loading