Disable Copy in CCP context menu for JsTree - jstree

How can I disable the "Copy" (but not cut / paste) functionality of the jsTree right click context menu?

This pretty much did the trick.
$("#housingTree").jstree({
"plugins": ["themes", "html_data", "ui", "crrm", "hotkeys", "contextmenu"],
"core": { "initially_open": ["phtml_1"] },
"contextmenu": {
"items": function ($node) {
return {
"Rename": {
"label": "Rename",
"action": function (obj) { this.rename(obj); }
},
"Create": {
"label": "Create",
"action": function (obj) { this.create(obj); }
},
"Delete": {
"label": "Delete",
"action": function (obj) { this.remove(obj); }
},
"Cut": {
"label": "Cut",
"action": function (obj) { this.cut(obj); }
},
"Paste": {
"label": "Paste",
"action": function (obj) { this.paste(obj); }
}
};
}
}
})

i dont know if the action functions are the default functions or custom functions, but that didnt work for me... anyway your post did set me in the right path! thanks!
this is how i did it, after finding another post:
"contextmenu": {
"items": function ($node) {
var tree = $("#html1Tree").jstree(true);
return {
"Rename": {
"label": "Rename",
"action": function (obj) {
tree.edit($node);
}
},
"Create": {
"label": "Create",
"action": function (obj) {
$node = tree.create_node($node);
tree.edit($node);
}
}
};
}
}
jsTree and Context Menu: modify items

The shorter approach could be
"contextmenu": {
"items": function(node) {
var defaultItems = $.jstree.defaults.contextmenu.items();
console.log("default items : "+JSON.stringify(defaultItems));
delete defaultItems.ccp.submenu.copy;
return defaultItems;
}
},
You can console.log(defaultItems). It wil print json representation of object. You can modify other properties also.

this is my easiest option.
All main code placed in "contextmenu.items" block.
$('#c-list').jstree({
"core": {
"themes": {"responsive": false},
"check_callback": true,
},
"types": {
"default": {
"icon": "fa fa-folder text-warning fa-lg"
},
"file": {
"icon": "fa fa-file text-warning fa-lg"
}
},
"contextmenu":{
'items' : function(node) {
var items = $.jstree.defaults.contextmenu.items();
items.ccp = false;
return items;
}
},
"plugins": ["contextmenu", "dnd", "types", "search", "wholerow","checkbox"]
});

Related

GitHub GraphQL API Filter on custom text field in Project V2

We are using GitHub Projects (Beta). I created a custom text field called oma-project. I want to use the API to filter on this field, e.g., oma-project: "P0001". This should return all issues with this value in the custom field.
Looking at the Projects (beta) docs, I can list the first n issues but I don't know how I can pass a filter based on the value of the custom field.
This is as far as I have gotten.
{
node(id: "nodeid") {
... on ProjectV2 {
items(first: 2) {
nodes {
fieldValues(first: 8) {
nodes {
... on ProjectV2ItemFieldTextValue {
text
field {
... on ProjectV2FieldCommon {
name
}
}
}
}
}
content {
... on Issue {
id
title
}
}
}
}
}
}
}
returns:
{
"data": {
"node": {
"items": {
"nodes": [
{
"fieldValues": {
"nodes": [
{},
{},
{},
{
"text": "Retrieve Notes via OData",
"field": {
"name": "Title"
}
},
{},
{
"text": "P9999",
"field": {
"name": "OMA Project"
}
}
]
},
"content": {
"id": "I_kwDOFT-pvM5AZNLm",
"title": "Retrieve Notes via OData"
}
},
{
"fieldValues": {
"nodes": [
{},
{},
{
"text": "Capex Approval Type",
"field": {
"name": "Title"
}
},
{},
{},
{
"text": "P0708",
"field": {
"name": "OMA Project"
}
}
]
},
"content": {
"id": "I_kwDOFT-pvM5K85HZ",
"title": "Capex Approval Type"
}
}
]
}
}
}
}
I'm having the same issue when working on a GitHub action to move a list of items from a status to another status, and it seems currently the API doesn't support ProjectV2 item filtering.
My current workaround is to query all the items from the project and then later filter out the results using jq or JavaScript

Implement I18n localization in Strapi local plugins

I generated a local plugin and created an article model using:
"pluginOptions": {
"i18n": {
"localized": true
}
},
inside his article.settings.json file, in order to make some specific fields translatables using the Internationalization(I18N) plugin
Problem is, while running the command:
strapi develop --watch-admin
I end up having the following errors:
error Something went wrong in the model "Article" with the attribute "localizations"
error TypeError: Cannot read property "uid" of undefined
Removing the "pluginOptions" instead, gives my local plugin running without any translatable field or articles__translations pivot that should be generated into my mysql database
"pluginOptions" is the very same parameter that gets generated into the model settings creating a collection type using the Content-Types Builder, but I can't have it to work while using it for a local plugin.
Here is my article.settings.json:
plugins/blog/models/article.settings.json
{
"kind": "collectionType",
"collectionName": "articles",
"info": {
"name": "article"
},
"options": {
"draftAndPublish": false,
"timestamps": true,
"populateCreatorFields": true,
"increments": true,
"comment": ""
},
"pluginOptions": {
"i18n": {
"localized": true
}
},
"attributes": {
"title": {
"pluginOptions": {
"i18n": {
"localized": true
}
},
"type": "string",
"required": true,
"maxLength": 255,
"minLength": 3
},
"slug": {
"pluginOptions": {
"i18n": {
"localized": true
}
},
"type": "uid",
"targetField": "title",
"required": true
},
"featured": {
"pluginOptions": {
"i18n": {
"localized": false
}
},
"type": "boolean",
"default": false
},
"published_date": {
"pluginOptions": {
"i18n": {
"localized": false
}
},
"type": "datetime"
},
}
}
You can use the content-type-builder plugin as a workaround. You would not create the content type under the content-types folder but create it programmatically.
As an example of a very simple tag content type:
{
"singularName": "tag",
"pluralName": "tags",
"displayName": "tag",
"description": "",
"draftAndPublish": false,
"pluginOptions": {
"i18n": {
"localized": true
}
},
"attributes": {
"label": {
"type": "string",
"pluginOptions": {
"i18n": {
"localized": true
}
},
"unique": true
}
}
}
Note, this schema of the json is a bit different from the ones in plugin/server/content-types.
Then you can create the content type programmatically like this:
import { Strapi } from "#strapi/strapi";
import tag from "../content-types/tag.json";
import page from "../content-types/page.json";
export default ({ strapi }: { strapi: Strapi }) => ({
async createContentComponent() {
if (!tag) return null;
try {
const components: any = [];
const contentType = await strapi
.plugin("content-type-builder")
.services["content-types"].createContentType({
contentType: tag,
components,
});
return contentType;
} catch (e) {
console.log("error", e);
return null;
}
},
});
This is exactly how the admin creates content types using the content builder UI.
And it works using the pluginOptions.i18n.localized: true.
One approach would be to do this, e.g., on the bootstrap phase of the plugin. Here you could also check whether or not the contents are created or not.
As a bonus, you can also create components that otherwise would not work.
Hope that helps.
Links:
Create components programmatically in a plugin: https://github.com/strapi/strapi-plugin-seo/blob/main/server/services/seo.js
Create content types:
https://github.com/strapi/strapi/blob/88caa92f878a068926255dd482180202f53fcdcc/packages/core/content-type-builder/server/controllers/content-types.js#L48
EDIT:
You could also keep the original schema and use this fn to transform it - at least for now as long as the other approach is not working:
https://github.com/strapi/strapi/blob/1eab2fb08c7a4d3d40a5a7ff3b2f137ce0afcf8a/packages/core/content-type-builder/server/services/content-types.js#L37

Write custom transform file for design tokens from Figma in Style Dictionary for Flutter

I have barebone Flutter 2.5 project and Figma design tokens which were exported via Figma Tokens.
Those design tokens look like this:
project\style_dictionary\properties\tokens.json
{
"borderWidth": {
"100": {
"value": "1.5",
"type": "borderWidth"
}
},
"opacity": {
"basic": {
"100": {
"value": "0.04",
"type": "opacity"
}
}
},
"colors": {
"basic": {
"red": {
"50": {
"value": "#ffebee",
"type": "color"
}
}
}
}
}
and Style Dictionary config which looks like this
project\style_dictionary\config.json
{
"source": [
"properties/*.json"
],
"platforms": {
"flutter": {
"transformGroup": "flutter",
"buildPath": "../lib/unique_file/",
"files": [
{
"destination": "style_dictionary.dart",
"format": "flutter/class.dart",
"className": "StyleDictionary"
}
]
},
"flutter-separate": {
"transformGroup": "flutter-separate",
"buildPath": "../lib/unique_file/",
"files": [
{
"destination": "style_dictionary_color.dart",
"format": "flutter/class.dart",
"className": "StyleDictionaryColor",
"type": "color",
"filter": {
"attributes": {
"category": "colors"
}
}
}
]
}
}
}
Running style-dictionary build in CMD in style_dictionary will generate next file
project\lib\unique_file\style_dictionary_color.dart
import 'dart:ui';
class StyleDictionaryColor {
StyleDictionaryColor._();
static const basicRed50 = #ffebee;
}
But in should be like that at the end
project\lib\unique_file\style_dictionary_color.dart
import 'dart:ui';
class StyleDictionaryColor {
StyleDictionaryColor._();
static const basicRed50 = Color(0xFFFFEBEE);
}
Question:
How and where can I create Style Dictionary transforms file to create right dart file with Color type of the static variable?
I cannot modify exported design tokens.
Create a project\build.js as a custom Transforms file. Logic of creation was used from default Flutter color transforms and Documentation
const StyleDictionary = require('style-dictionary')
const baseConfig = require('./style_dictionary/config.json')
const Color = require('tinycolor2')
StyleDictionary.registerTransform({
name: 'colors/hex8flutter',
type: 'value',
matcher: prop => {
return prop.attributes.category === 'colors'
},
transformer: prop => {
var str = Color(prop.value).toHex8().toUpperCase();
return `Color(0x${str.slice(6)}${str.slice(0, 6)})`;
},
})
const StyleDictionaryExtended = StyleDictionary.extend(baseConfig)
StyleDictionaryExtended.buildAllPlatforms()
Modify project\style_dictionary\config.json so it can be executed from project directory and include new transforms - "transformColorsToColor" together with other transforms from Flutter
{
"source": [
"style_dictionary/properties/*.json"
],
"platforms": {
"flutter": {
"transforms": ["attribute/cti", "name/cti/camel", "color/hex8flutter", "size/flutter/remToDouble", "content/flutter/literal", "asset/flutter/literal", "font/flutter/literal", "colors/hex8flutter"],
"buildPath": "lib/unique_file/",
"files": [
{
"destination": "style_dictionary.dart",
"format": "flutter/class.dart",
"className": "StyleDictionary"
}
]
},
"flutter-separate": {
"transforms": ["attribute/cti", "name/ti/camel", "color/hex8flutter", "size/flutter/remToDouble", "content/flutter/literal", "asset/flutter/literal", "font/flutter/literal", "colors/hex8flutter"],
"buildPath": "lib/unique_file/",
"files": [
{
"destination": "style_dictionary_color.dart",
"format": "flutter/class.dart",
"className": "StyleDictionaryColor",
"type": "color",
"filter": {
"attributes": {
"category": "colors"
}
}
}
]
}
}
}
Run npm init with all default answers
Run npm install --save tinycolor2
Run node build.js

Promises do not work (for me)

Probably I'm missing something basic here. Scenario goes like this:
Within the root view controller of my application (App.controller.js, onInit function) I'm performing a series of read operations on a named model in order to have additional data ready mainly for use by formatters in subsequent views. What I have done is using promises to make sure that data will be ready.
Problem is that application occasionally crashes when the initial view with pattern "" (Worklist.view.xml in my case) is loaded after the root view (App.view.xml) because the formatter function can't find the data expected. Added a few break-points and observed the debugger:
stopping at the first read function
stopping at the promises condition at the end
stopping (and throwing error) at the formatter function at the subsequent view
stopping in the success function of oData read (resolve)
page freezes afterwards as result of the exception thrown above
"Normal" flow, when application doesn't crash goes like this:
stopping at the first read function
stopping at the promises condition at the end
stopping in the success function of oData read (resolve)
stopping at the readyToGo function (it's there just for temporary debugging)
stopping at the formatter function at the subsequent view
page display, everything in order
Judging by the above, I have reached the conclusion that my promises do not work. Any ideas?
sap.ui.define([
"kristal/apps/agreements/controller/BaseController",
"sap/ui/model/json/JSONModel"
], function (BaseController, JSONModel) {
"use strict";
/* PROMISE VARIABLES */
var oModelTypeDataDeferred = jQuery.Deferred();
var oModelStatusDataDeferred = jQuery.Deferred();
var oModelRoleDataDeferred = jQuery.Deferred();
var oModelRefDataDeferred = jQuery.Deferred();
var oModelExtOrgDataDeferred = jQuery.Deferred();
var oModelInvolvementDataDeferred = jQuery.Deferred();
return BaseController.extend("kristal.apps.agreements.controller.App", {
onInit: function () {
/* CALLED AFTER PROMISES HAVE BEEN FULFILLED */
var readyToGo = function() {
jQuery.sap.log.error("Ready!");
};
var oViewModel;
var fnSetAppNotBusy;
var iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
var oViewModel = new JSONModel({
busy: true,
delay: 0
});
this.setModel(oViewModel, "appView");
fnSetAppNotBusy = function() {
oViewModel.setProperty("/busy", false);
oViewModel.setProperty("/delay", iOriginalBusyDelay);
};
this.getOwnerComponent().getModel().metadataLoaded().then(fnSetAppNotBusy);
var oModel = this.getOwnerComponent().getModel("f4");
/* oData READ OPS */
oModel.metadataLoaded().then(function(){
// Initialize additional data
var sPath = "/Agreement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelTypeDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Agreement_StatusesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelStatusDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Role_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRoleDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Reference_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/External_OrganizationsSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelRefDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
sPath = "/Involvement_TypesSet";
oModel.read(sPath, {
success: function(oData, oResponse) {
oModelInvolvementDataDeferred.resolve();
},
error: function(oError) {
jQuery.sap.log.error("Error", oError);
}
});
/* IF ALL PROMISES FULFILLED, PROCEED */
jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelRoleDataDeferred, oModelRefDataDeferred, oModelExtOrgDataDeferred, oModelInvolvementDataDeferred)
.done().then(jQuery.proxy(readyToGo, this));
},
// ...
});
});
manifest.json:
{
"_version": "1.4.0",
"sap.app": {
"id": "kristal.apps.agreements",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion": {
"version": "1.0.0"
},
"dataSources": {
"mainService": {
"uri": "/DEV/sap/opu/odata/SAP/ZCONTRACTS_SRV/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "localService/metadata.xml"
}
}
},
"sourceTemplate": {
"id": "sap.ui.ui5-template-plugin.1worklist",
"version": "1.38.3"
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "sap-icon://task",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal"
]
},
"sap.ui5": {
"rootView": {
"viewName": "kristal.apps.agreements.view.App",
"type": "XML",
"id": "app",
"async": true
},
"dependencies": {
"minUI5Version": "1.38.0",
"libs": {
"sap.ui.core": {
"minVersion": "1.38.0"
},
"sap.m": {
"minVersion": "1.38.0"
},
"sap.ushell": {
"minVersion": "1.38.0"
},
"sap.collaboration": {
"minVersion": "1.38",
"lazy": true
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "kristal.apps.agreements.i18n.i18n"
}
},
"": {
"dataSource": "mainService",
"preload": true,
"settings": {
"defaultBindingMode": "TwoWay"
}
},
"f4": {
"dataSource": "mainService",
"preload": true,
"settings": {
"metadataUrlParams": {
"sap-documentation": "heading"
},
"defaultBindingMode": "TwoWay"
}
}
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "kristal.apps.agreements.view",
"controlId": "app",
"controlAggregation": "pages",
"bypassed": {
"target": [
"notFound"
]
},
"async": true
},
"routes": [{
"pattern": "",
"name": "worklist",
"target": [
"worklist"
]
}, {
"pattern": "AgreementsSet/{objectId}",
"name": "object",
"target": [
"object"
]
}],
"targets": {
"worklist": {
"viewName": "Worklist",
"viewId": "worklist",
"viewLevel": 1
},
"object": {
"viewName": "Object",
"viewId": "object",
"viewLevel": 2
},
"objectNotFound": {
"viewName": "ObjectNotFound",
"viewId": "objectNotFound"
},
"notFound": {
"viewName": "NotFound",
"viewId": "notFound"
}
}
}
},
"sap.platform.abap": {
"uri": "/sap/bc/ui5_ui5/sap/zctr_contr_mnt/webapp",
"_version": "1.1.0"
}
}
Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/Device",
"kristal/apps/agreements/model/models",
"kristal/apps/agreements/controller/ErrorHandler"
], function(UIComponent, Device, models, ErrorHandler) {
"use strict";
return UIComponent.extend("kristal.apps.agreements.Component", {
metadata: {
manifest: "json"
},
init: function() {
UIComponent.prototype.init.apply(this, arguments);
this._oErrorHandler = new ErrorHandler(this);
this.setModel(models.createDeviceModel(), "device");
this.setModel(models.createFLPModel(), "FLP");
this.getRouter().initialize();
},
destroy: function() {
this._oErrorHandler.destroy();
// call the base component's destroy function
UIComponent.prototype.destroy.apply(this, arguments);
},
getContentDensityClass: function() {
if (this._sContentDensityClass === undefined) {
// check whether FLP has already set the content density class; do nothing in this case
if (jQuery(document.body).hasClass("sapUiSizeCozy") || jQuery(document.body).hasClass("sapUiSizeCompact")) {
this._sContentDensityClass = "";
} else if (!Device.support.touch) { // apply "compact" mode if touch is not supported
this._sContentDensityClass = "sapUiSizeCompact";
} else {
// "cozy" in case of touch support; default for most sap.m controls, but needed for desktop-first controls like sap.ui.table.Table
this._sContentDensityClass = "sapUiSizeCozy";
}
}
return this._sContentDensityClass;
}
});
});
It was all about moving functionality from the root view to component.js and putting the router initialization into the promise conditions, thank you experts

How to pick up data from json with multiple level with scala

I want to pick up data from the json, but i can not code it in scala, i can only write it in php, because it is very simple to use, but i have no idea how can i do the same thing in scala. please help me out.
{
"home": {
"type": "literal",
"options": {
"route": "\/",
"defaults": {
"controller": "Apiv1\\Controller\\Index",
"action": "index"
}
}
},
"praise": {
"type": "literal",
"options": {
"route": "\/apiv1\/praise",
"defaults": {
"controller": "Apiv1\\Controller\\Praise",
"action": "index"
}
},
"may_terminate": true,
"child_routes": {
"status": {
"type": "literal",
"options": {
"route": "\/status",
"defaults": {
"action": "status"
}
}
}
}
},
"admin": {
"type": "literal",
"options": {
"route": "\/admin",
"defaults": {
"controller": "Admin\\Controller\\Index",
"action": "index"
}
},
"may_terminate": true,
"child_routes": {
"routes": {
"type": "literal",
"options": {
"route": "\/routes",
"defaults": {
"controller": "Admin\\Controller\\Routes",
"action": "index"
}
},
"may_terminate": true,
"child_routes": {
"list": {
"type": "literal",
"options": {
"route": "\/list",
"defaults": {
"action": "list"
}
}
}
}
}
}
}
}
I want to pick up the route field from the json, and i would like to list all routes
here is my php version function
function parseRoute($a, $pre = '', &$urls)
{
foreach ($a as $k => $v) {
$route = $pre . $v['options']['route'];
$urls[] = $route;
if (isset($v['child_routes']) && is_array($v['child_routes'])) {
$this->parseRoute($v['child_routes'], $route, $urls);
}
$route = null;
}
}
$urls = array();
var_dump(parseRoute(json_decode($data), '', $urls));
The best thing to do is to use one of the existing JSON libraries for Scala. Here is related question describing your options:
What JSON library to use in Scala?
Next is an example of using Lift-JSON. See the link, there are many examples. Here is what you can do:
import net.liftweb.json._
val rawJson = """{
"home":{
"type":"literal",
"options":{
"route":"/",
"defaults":{
"controller":"Apiv1\\Controller\\Index",
"action":"index"
}
}
},
"praise":{
"type":"literal",
"options":{
"route":"/apiv1/praise",
"defaults":{
"controller":"Apiv1\\Controller\\Praise",
"action":"index"
}
},
"may_terminate":true,
"child_routes":{
"status":{
"type":"literal",
"options":{
"route":"/status",
"defaults":{
"action":"status"
}
}
}
}
},
"admin":{
"type":"literal",
"options":{
"route":"/admin",
"defaults":{
"controller":"Admin\\Controller\\Index",
"action":"index"
}
},
"may_terminate":true,
"child_routes":{
"routes":{
"type":"literal",
"options":{
"route":"/routes",
"defaults":{
"controller":"Admin\\Controller\\Routes",
"action":"index"
}
},
"may_terminate":true,
"child_routes":{
"list":{
"type":"literal",
"options":{
"route":"/list",
"defaults":{
"action":"list"
}
}
}
}
}
}
}
}"""
val json = parse(rawJson)
val routeList = json \\ "route"
// which returns a structure like this:
JObject(List(JField(route,JString(/)), JField(route,JString(/apiv1/praise)), JField(route,JString(/status)), JField(route,JString(/admin)), JField(route,JString(/routes)), JField(route,JString(/list))))
// which is a JSON object
// if you want a list of routes as strings as in your example extract them this way now:
val routeList: List[String] = routeObject \\ classOf[JString]
// which returns:
List[String] = List(/, /apiv1/praise, /status, /admin, /routes, /list)
Note that I'm assuming that routes can be at any level of nesting in JSON doc (you might want to enforce certain level or parent of the 'route'). I also assume that all routes are Strings and ignore the ones which are not - if you want more options you can pattern match on the type of route using derivative classes of JValue: JArray, JString, JObject, etc.