Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
89051f5
feat(plugin): add sandbox / allowed_hosts / permissions accessors to …
nameless-mc Apr 23, 2026
7432787
feat(plugin-info): surface sandbox / allowed_hosts / permissions
nameless-mc Apr 23, 2026
a4c311a
feat(plugin-upload): include sandbox fields in installation summary
nameless-mc Apr 23, 2026
ccb533a
test(plugin-pack): add e2e scenarios for sandbox pack and plugin info
nameless-mc Apr 23, 2026
797f087
docs(plugin): add hidden experimental sandbox page (en/ja)
nameless-mc Apr 23, 2026
43a8650
fix(plugin-pack): add input id to match label for in sandbox e2e fixture
nameless-mc Apr 23, 2026
1147206
test(plugin-upload): cover buildSandboxSummary output (all/none/place…
nameless-mc Apr 23, 2026
97a91a3
refactor(plugin): share installation summary between info and upload
nameless-mc Apr 27, 2026
00b9892
refactor(plugin-info): extract buildJsonInfo and document summary pla…
nameless-mc May 1, 2026
2699cec
test(plugin-info): cover buildJsonInfo unit and add e2e json scenario
nameless-mc May 1, 2026
40bc402
fix(plugin): treat omitted permission children as (not set), not (none)
nameless-mc May 11, 2026
b7da05a
refactor(plugin-upload): build installation summary lines with spread
nameless-mc May 11, 2026
cb453d6
refactor(plugin-manifest): move sandbox accessor note to interface
nameless-mc May 11, 2026
6c6b2d9
deps: update plugin-manifest-validator to 11.2.0
nameless-mc May 18, 2026
e9b7747
refactor(plugin-manifest): reuse ManifestPermissions type in v2 and info
nameless-mc May 19, 2026
052a1d6
test(plugin-summary): drop misleading no-op assertion
nameless-mc May 19, 2026
8a0de0c
chore(plugin): bump sandbox fixture $schema to validator 11.2.0
nameless-mc May 21, 2026
bd914e9
test(plugin-manifest): cover sandbox: true without allowed_hosts as i…
nameless-mc May 21, 2026
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
665 changes: 665 additions & 0 deletions features/assets/plugin_project_sandbox/css/51-modern-default.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions features/assets/plugin_project_sandbox/css/config.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.settings-heading {
padding: 1em 0;
}

.kintoneplugin-input-text {
width: 20em;
}
10 changes: 10 additions & 0 deletions features/assets/plugin_project_sandbox/css/desktop.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.plugin-space-heading {
font-size: 1.5rem;
margin: 0.8rem;
}
.plugin-space-message {
display: inline-block;
font-size: 1.2em;
margin: 0.8rem;
margin-top: 0;
}
10 changes: 10 additions & 0 deletions features/assets/plugin_project_sandbox/css/mobile.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.plugin-space-heading {
font-size: 1.5rem;
margin: 0.8rem;
}
.plugin-space-message {
display: inline-block;
font-size: 1.2em;
margin: 0.8rem;
margin-top: 0;
}
16 changes: 16 additions & 0 deletions features/assets/plugin_project_sandbox/html/config.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<section class="settings">
<h2 class="settings-heading">Settings for hello-kintone</h2>
<p class="kintoneplugin-desc">This message is displayed on the app page after the app has been updated.</p>
<form class="js-submit-settings">
<p class="kintoneplugin-row">
<label for="message">
Message:
<input id="message" type="text" class="js-text-message kintoneplugin-input-text">
</label>
</p>
<p class="kintoneplugin-row">
<button type="button" class="js-cancel-button kintoneplugin-button-dialog-cancel">Cancel</button>
<button class="kintoneplugin-button-dialog-ok">Save</button>
</p>
</form>
</section>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions features/assets/plugin_project_sandbox/js/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
(function (PLUGIN_ID) {
const formEl = document.querySelector(".js-submit-settings");
const cancelButtonEl = document.querySelector(".js-cancel-button");
const messageEl = document.querySelector(".js-text-message");
if (!(formEl && cancelButtonEl && messageEl)) {
throw new Error("Required elements do not exist.");
}

const config = kintone.plugin.app.getConfig(PLUGIN_ID);
if (config.message) {
messageEl.value = config.message;
}

formEl.addEventListener("submit", (e) => {
e.preventDefault();
kintone.plugin.app.setConfig({ message: messageEl.value }, () => {
alert("The plug-in settings have been saved. Please update the app!");
window.location.href = "../../flow?app=" + kintone.app.getId();
});
});

cancelButtonEl.addEventListener("click", () => {
window.location.href = "../../" + kintone.app.getId() + "/plugin/";
});
})(kintone.$PLUGIN_ID);
22 changes: 22 additions & 0 deletions features/assets/plugin_project_sandbox/js/desktop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(function (PLUGIN_ID) {
kintone.events.on("app.record.index.show", () => {
const spaceEl = kintone.app.getHeaderSpaceElement();
if (spaceEl === null) {
throw new Error("The header element is unavailable on this page.");
}

const fragment = document.createDocumentFragment();
const headingEl = document.createElement("h3");
const messageEl = document.createElement("p");

const config = kintone.plugin.app.getConfig(PLUGIN_ID);
messageEl.textContent = config.message;
messageEl.classList.add("plugin-space-message");
headingEl.textContent = "Hello kintone plugin!";
headingEl.classList.add("plugin-space-heading");

fragment.appendChild(headingEl);
fragment.appendChild(messageEl);
spaceEl.appendChild(fragment);
});
})(kintone.$PLUGIN_ID);
22 changes: 22 additions & 0 deletions features/assets/plugin_project_sandbox/js/mobile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(function (PLUGIN_ID) {
kintone.events.on("mobile.app.record.index.show", () => {
const spaceEl = kintone.mobile.app.getHeaderSpaceElement();
if (spaceEl === null) {
throw new Error("The header element is unavailable on this page.");
}

const fragment = document.createDocumentFragment();
const headingEl = document.createElement("h3");
const messageEl = document.createElement("p");

const config = kintone.plugin.app.getConfig(PLUGIN_ID);
messageEl.textContent = config.message;
messageEl.classList.add("plugin-space-message");
headingEl.textContent = "Hello kintone plugin!";
headingEl.classList.add("plugin-space-heading");

fragment.appendChild(headingEl);
fragment.appendChild(messageEl);
spaceEl.appendChild(fragment);
});
})(kintone.$PLUGIN_ID);
36 changes: 36 additions & 0 deletions features/assets/plugin_project_sandbox/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "https://raw.githubusercontent.com/kintone/js-sdk/%40kintone/plugin-manifest-validator%4011.2.0/packages/plugin-manifest-validator/manifest-schema.json",
"manifest_version": 1,
"version": 1,
"type": "APP",
"sandbox": true,
"allowed_hosts": ["https://example.com", "wss://example.com/ws/*"],
"permissions": {
"js_api": ["app:read", "network:connect"],
"rest_api": ["app_record:read"]
},
"desktop": {
"js": ["js/desktop.js"],
"css": ["css/51-modern-default.css", "css/desktop.css"]
},
"icon": "image/icon.png",
"config": {
"html": "html/config.html",
"js": ["js/config.js"],
"css": ["css/51-modern-default.css", "css/config.css"],
"required_params": ["message"]
},
"name": {
"en": "hello-kintone-sandbox"
},
"description": {
"en": "Sandbox-enabled plugin sample."
},
"homepage_url": {
"en": "https://example.com/en/"
},
"mobile": {
"js": ["js/mobile.js"],
"css": ["css/mobile.css"]
}
}
15 changes: 15 additions & 0 deletions features/assets/plugin_project_sandbox/private.ppk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDdjV2LPB6D8OQBnJDRcRl4u5FpwVmAesqRPCrDt6UyjGl8V0Mb
c4TAo4IEmuiftgCeyPkSIzPicEW4fxySqr7U8YZPkSdvB6WaOpbuiRIqryS9scHO
wDOtSzifo9+UpZhofx155te+88VTBDIU2zCIdhmShvwr5y0L3MlcF4BTxwIDAQAB
AoGASURbwBTknouGS4YkWi8F1mhpIUkguR1iaf80wT61Me8/XzBYb/aW20H3WGCG
N3Lv55Lc04Oyv9qTI/1dTJ+Mta+ZfkAOkEp+XwF3jW1qDc25TZsP8wXOW5wSRdCs
N4MIpZXLq0OaEC5xw7C8Dt8f+BAhPkUAzD8gehbfts4UybkCQQDuV4uXdBfVcDLW
srEn1oNyIJ3uhFzvZMfEkmvxSQNpdbcL1kfpnFoSwImYN5r6AwMOYgDDjI+qL91j
NXZ/zs1dAkEA7fdhk1Qn7JHHcl3ML7w/SL59JLqpcOEF4rZ66ZKDfqKDu5+JN5Q+
9+86es4sl4tLN+kamgvR9bUOKkZU6R4vcwJBANjTsf1tswUMlmN1mu74Gwrnm2XS
6s0qrQYqgqK2XrFBUu4k2bUv9U2b9VESPR33QX+DLti3djdIZiqMB6rME00CQQDZ
gWnAfgVX6A9C65T8dLXrSaGc9rh1Ilh81ooWAAMMtoJt9e43zNqZSCJNqTF8+qav
3fKgpvkr+meOIGbwBNUdAkEA2sPlzdNLYrA6R0Bsxgwk5XixTlzYZ+BIHrrRGSUM
UsbQmXsHSbhA6rNWeBEO4fdbmPZOUbP0mDbPQpZA9TQJ2A==
-----END RSA PRIVATE KEY-----
Comment thread
nameless-mc marked this conversation as resolved.
34 changes: 34 additions & 0 deletions features/plugin/pack.feature
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,37 @@ Feature: plugin pack
When I run the command with args "plugin pack --input ./src/manifest.json --private-key ./src/private.ppk --output ./dist/plugin.zip"
Then I should get the exit code is zero
And I have a file at "./dist/plugin.zip"

Scenario: Pack a plugin with sandbox, allowed_hosts and permissions
Given An asset with key "plugin_project_sandbox" is available as "src"
When I run the command with args "plugin pack --input ./src/manifest.json --private-key ./src/private.ppk"
Then I should get the exit code is zero
And I have a file at "plugin.zip"

Scenario: Plugin info surfaces sandbox, allowed_hosts and permissions
Given An asset with key "plugin_project_sandbox" is available as "src"
When I run the command with args "plugin pack --input ./src/manifest.json --private-key ./src/private.ppk"
Then I should get the exit code is zero
And I have a file at "plugin.zip"
When I run the command with args "plugin info --input ./plugin.zip"
Then I should get the exit code is zero
And The output message should match with the pattern:
"""
sandbox: true
allowed_hosts: https://example\.com, wss://example\.com/ws/\*
permissions\.js_api: app:read, network:connect
permissions\.rest_api: app_record:read
"""

Scenario: Plugin info --format json surfaces sandbox-related keys with snake_case names
Given An asset with key "plugin_project_sandbox" is available as "src"
When I run the command with args "plugin pack --input ./src/manifest.json --private-key ./src/private.ppk"
Then I should get the exit code is zero
And I have a file at "plugin.zip"
When I run the command with args "plugin info --input ./plugin.zip --format json"
Then I should get the exit code is zero
And The output message should match with the pattern: "\"sandbox\": true"
And The output message should match with the pattern: "\"allowed_hosts\": \["
And The output message should match with the pattern: "\"permissions\":"
And The output message should match with the pattern: "\"js_api\":"
And The output message should match with the pattern: "\"rest_api\":"
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@
},
"dependencies": {
"@inquirer/prompts": "7.10.1",
"@kintone/plugin-manifest-validator": "11.1.1",
"@kintone/plugin-manifest-validator": "11.2.0",
"@kintone/rest-api-client": "6.1.6",
"chalk": "4.1.2",
"chokidar": "4.0.3",
Expand Down
Loading
Loading