Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ad780703ab | |||
| 038afb3f9c | |||
| f2620fda77 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,5 +1,30 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.3.3 - 2026-07-23
|
||||||
|
|
||||||
|
- Let the OneNote application use the full width supplied by the shared
|
||||||
|
Toolbox shell, matching the shell bar's `min(100%, 90rem)` content span
|
||||||
|
instead of retaining the former 76rem application cap.
|
||||||
|
|
||||||
|
## 0.3.2 - 2026-07-23
|
||||||
|
|
||||||
|
- Upgrade the Toolbox contract, React shell, and validation testkit to 0.2.2,
|
||||||
|
pinned to SDK revision `53c40a61ba1581246f65773fcbb1c1cfd31ac98e`.
|
||||||
|
- Move the Toolbox icon and `add·ideas Toolbox` label to the fixed far-left
|
||||||
|
block and place Help, the OneNote-specific Gitea source link, Apps, and
|
||||||
|
Personalize in that order in the fixed far-right cluster while retaining the
|
||||||
|
centered app title and tagline.
|
||||||
|
- Use the shared portal-style Personalize appearance panel; catalogue counts
|
||||||
|
and preference import/export remain portal-only controls.
|
||||||
|
|
||||||
|
## 0.3.1 - 2026-07-23
|
||||||
|
|
||||||
|
- Upgrade the Toolbox contract, React shell, and validation testkit to 0.2.1.
|
||||||
|
- Adopt the stable shared top bar: the fixed left cluster contains Personalize,
|
||||||
|
Apps, the OneNote-specific Gitea source link, and Help; the app title and one
|
||||||
|
tagline remain centered; and the fixed far-right block contains the Toolbox
|
||||||
|
icon and `add·ideas Toolbox` label.
|
||||||
|
|
||||||
## 0.3.0 - 2026-07-23
|
## 0.3.0 - 2026-07-23
|
||||||
|
|
||||||
- Adopt the Toolbox SDK 0.2.0 shared header with standard Help and app-specific
|
- Adopt the Toolbox SDK 0.2.0 shared header with standard Help and app-specific
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -9,7 +9,14 @@ It is also an independent application in the add·ideas Toolbox contract. The
|
|||||||
source uses the Toolbox SDK shell and manifest, builds with Vite `base: './'`,
|
source uses the Toolbox SDK shell and manifest, builds with Vite `base: './'`,
|
||||||
and is delivered to Toolbox Portal as a checksummed static ZIP.
|
and is delivered to Toolbox Portal as a checksummed static ZIP.
|
||||||
|
|
||||||
## What version 0.3.0 supports
|
Version 0.3.3 uses the stable shared top bar, with the Toolbox icon and
|
||||||
|
`add·ideas Toolbox` label in a fixed far-left block; the app title and one
|
||||||
|
tagline centered; and Help, the OneNote source link, Apps, and Personalize in a
|
||||||
|
fixed far-right cluster. Personalize uses the shared portal-style appearance
|
||||||
|
panel while catalogue counts and preference import/export stay in the portal.
|
||||||
|
The application content uses the same `min(100%, 90rem)` span as the shell bar.
|
||||||
|
|
||||||
|
## What version 0.3.3 supports
|
||||||
|
|
||||||
- Desktop revision-store and unfragmented FSSHTTPB package-store `.one`
|
- Desktop revision-store and unfragmented FSSHTTPB package-store `.one`
|
||||||
sections from the tested producer families.
|
sections from the tested producer families.
|
||||||
@@ -80,7 +87,7 @@ supplied through the SDK's `?toolbox=` context mechanism. The app uses the SDK
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm run release:artifact
|
npm run release:artifact
|
||||||
(cd release && sha256sum -c onenote-tools-0.3.0.sha256)
|
(cd release && sha256sum -c onenote-tools-0.3.3.sha256)
|
||||||
```
|
```
|
||||||
|
|
||||||
The ZIP root contains the built static app and manifest plus the changelog,
|
The ZIP root contains the built static app and manifest plus the changelog,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Corresponding source
|
# Corresponding source
|
||||||
|
|
||||||
The corresponding source for OneNote Tools 0.3.0 is the `v0.3.0` tag:
|
The corresponding source for OneNote Tools 0.3.3 is the `v0.3.3` tag:
|
||||||
|
|
||||||
https://git.add-ideas.de/zemion/onenote-tools/src/tag/v0.3.0
|
https://git.add-ideas.de/zemion/onenote-tools/src/tag/v0.3.3
|
||||||
|
|
||||||
Build the release from that tag with Node.js 22 or newer:
|
Build the release from that tag with Node.js 22 or newer:
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
The production application uses:
|
The production application uses:
|
||||||
|
|
||||||
- `@add-ideas/toolbox-contract` 0.2.0, Apache-2.0;
|
- `@add-ideas/toolbox-contract` 0.2.2, Apache-2.0;
|
||||||
- `@add-ideas/toolbox-shell-react` 0.2.0, Apache-2.0;
|
- `@add-ideas/toolbox-shell-react` 0.2.2, Apache-2.0;
|
||||||
- fflate 0.8.3, MIT;
|
- fflate 0.8.3, MIT;
|
||||||
- React, React DOM, and Scheduler, MIT.
|
- React, React DOM, and Scheduler, MIT.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Format support
|
# Format support
|
||||||
|
|
||||||
## Version 0.3.0 support matrix
|
## Version 0.3.3 support matrix
|
||||||
|
|
||||||
| Input or feature | Status | Tested evidence and boundary |
|
| Input or feature | Status | Tested evidence and boundary |
|
||||||
| -------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- |
|
| -------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# Specifications and pinned references
|
# Specifications and pinned references
|
||||||
|
|
||||||
Version 0.3.0 records these immutable implementation revisions:
|
Version 0.3.3 records these immutable implementation revisions:
|
||||||
|
|
||||||
| Repository | Exact revision | Use |
|
| Repository | Exact revision | Use |
|
||||||
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
| ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------- |
|
||||||
| [`toolbox-sdk`](https://git.add-ideas.de/zemion/toolbox-sdk/src/commit/5e206baf42dfae5a00f2743fb2cc501bb12d9b7a) | `5e206baf42dfae5a00f2743fb2cc501bb12d9b7a` | App contract, React shell, manifest schema/testkit, and nested-path behavior |
|
| [`toolbox-sdk`](https://git.add-ideas.de/zemion/toolbox-sdk/src/commit/53c40a61ba1581246f65773fcbb1c1cfd31ac98e) | `53c40a61ba1581246f65773fcbb1c1cfd31ac98e` | App contract, React shell, manifest schema/testkit, and nested-path behavior |
|
||||||
| [`toolbox-portal`](https://git.add-ideas.de/zemion/toolbox-portal/src/commit/d46f1b61fb85a18299b6b8af2148dcd991ef6b05) | `d46f1b61fb85a18299b6b8af2148dcd991ef6b05` | Reviewed ZIP shape, exact checksum lock, independent-app assembly, and nginx deployment model |
|
| [`toolbox-portal`](https://git.add-ideas.de/zemion/toolbox-portal/src/commit/d46f1b61fb85a18299b6b8af2148dcd991ef6b05) | `d46f1b61fb85a18299b6b8af2148dcd991ef6b05` | Reviewed ZIP shape, exact checksum lock, independent-app assembly, and nginx deployment model |
|
||||||
| [`onenote.rs`](https://github.com/msiemens/onenote.rs/tree/5138a39a3f4e72b840932f9872fecde52fa9da60) | `5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected desktop/FSSHTTPB OneStore and MS-ONE structures adapted into TypeScript |
|
| [`onenote.rs`](https://github.com/msiemens/onenote.rs/tree/5138a39a3f4e72b840932f9872fecde52fa9da60) | `5138a39a3f4e72b840932f9872fecde52fa9da60` | Selected desktop/FSSHTTPB OneStore and MS-ONE structures adapted into TypeScript |
|
||||||
| [`rust-cab`](https://github.com/mdsteele/rust-cab/tree/c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2) | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2` | CAB structures, checksum, enumeration/extraction, MSZIP history, and unit fixtures |
|
| [`rust-cab`](https://github.com/mdsteele/rust-cab/tree/c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2) | `c5839f5fdfa4c4e7cc9b22f570c79c96af0560e2` | CAB structures, checksum, enumeration/extraction, MSZIP history, and unit fixtures |
|
||||||
|
|||||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -1,22 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "onenote-tools",
|
"name": "onenote-tools",
|
||||||
"version": "0.3.0",
|
"version": "0.3.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "onenote-tools",
|
"name": "onenote-tools",
|
||||||
"version": "0.3.0",
|
"version": "0.3.3",
|
||||||
"license": "MPL-2.0 AND LGPL-2.1-only",
|
"license": "MPL-2.0 AND LGPL-2.1-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@add-ideas/toolbox-contract": "0.2.0",
|
"@add-ideas/toolbox-contract": "0.2.2",
|
||||||
"@add-ideas/toolbox-shell-react": "0.2.0",
|
"@add-ideas/toolbox-shell-react": "0.2.2",
|
||||||
"fflate": "^0.8.3",
|
"fflate": "^0.8.3",
|
||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@add-ideas/toolbox-testkit": "0.2.0",
|
"@add-ideas/toolbox-testkit": "0.2.2",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
@@ -42,18 +42,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@add-ideas/toolbox-contract": {
|
"node_modules/@add-ideas/toolbox-contract": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-contract/-/0.2.0/toolbox-contract-0.2.0.tgz",
|
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-contract/-/0.2.2/toolbox-contract-0.2.2.tgz",
|
||||||
"integrity": "sha512-up+wY+ft1L7TbXrflcTeTOwEdcFwHBWFlGFj8skQvcLy5z2mDBpd6/7PVQKDvDTkiODu2npviHm6AFglFw+17Q==",
|
"integrity": "sha512-VcZ8j4O2PgFaIYgxs6r9u0uPxA+hHKwhCW+omfeVCtbjAAYhH2KhRlBGm0ERVVYcK5kchyzZLXrC4LKWRotVzg==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@add-ideas/toolbox-shell-react": {
|
"node_modules/@add-ideas/toolbox-shell-react": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.2.0/toolbox-shell-react-0.2.0.tgz",
|
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-shell-react/-/0.2.2/toolbox-shell-react-0.2.2.tgz",
|
||||||
"integrity": "sha512-qYR+OBXX8rfB+BYCsUbpiCzo2xK12SIPWVNXHre158Da5uT6usr8rRvp5qa5u2oQJ50PNzlXyXMyTeRp0Vz5wg==",
|
"integrity": "sha512-w/xbLCd50a2Jq7vQ9Z9ygUOuqlOCRkIYlk4vSJx0mf4REJNeMYi3PE2MbaLUC4DkQWyrmatsa5HNT89o0l91BA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@add-ideas/toolbox-contract": "0.2.0"
|
"@add-ideas/toolbox-contract": "0.2.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=18 <20",
|
"react": ">=18 <20",
|
||||||
@@ -61,13 +61,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@add-ideas/toolbox-testkit": {
|
"node_modules/@add-ideas/toolbox-testkit": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.2",
|
||||||
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-testkit/-/0.2.0/toolbox-testkit-0.2.0.tgz",
|
"resolved": "https://git.add-ideas.de/api/packages/zemion/npm/%40add-ideas%2Ftoolbox-testkit/-/0.2.2/toolbox-testkit-0.2.2.tgz",
|
||||||
"integrity": "sha512-+BSiWgS0F3vpjPgty9B4UtfdZTRbo97ZElb2BSb0ry57fS3cE7w7pfJW1Mzk/gV1/JChspw3JBY+4ZJDBhkiFw==",
|
"integrity": "sha512-ZxrRYiJI/j5aXwcd3mQItgDl1iOJ6N26+MpIG18qVZNwKKFCTCfSTzgzRooPt8rRc1MQYTPo4c+l/QpOWuTXxA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@add-ideas/toolbox-contract": "0.2.0"
|
"@add-ideas/toolbox-contract": "0.2.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"toolbox-check": "dist/cli.js"
|
"toolbox-check": "dist/cli.js"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "onenote-tools",
|
"name": "onenote-tools",
|
||||||
"version": "0.3.0",
|
"version": "0.3.3",
|
||||||
"description": "A local-first browser reader and exporter for OneNote files.",
|
"description": "A local-first browser reader and exporter for OneNote files.",
|
||||||
"license": "MPL-2.0 AND LGPL-2.1-only",
|
"license": "MPL-2.0 AND LGPL-2.1-only",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -27,14 +27,14 @@
|
|||||||
"check": "npm run manifest:check && npm run typecheck && npm run lint && npm run format:check && npm run test && npm run build && npm run toolbox:check"
|
"check": "npm run manifest:check && npm run typecheck && npm run lint && npm run format:check && npm run test && npm run build && npm run toolbox:check"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@add-ideas/toolbox-contract": "0.2.0",
|
"@add-ideas/toolbox-contract": "0.2.2",
|
||||||
"@add-ideas/toolbox-shell-react": "0.2.0",
|
"@add-ideas/toolbox-shell-react": "0.2.2",
|
||||||
"fflate": "^0.8.3",
|
"fflate": "^0.8.3",
|
||||||
"react": "^19.2.6",
|
"react": "^19.2.6",
|
||||||
"react-dom": "^19.2.6"
|
"react-dom": "^19.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@add-ideas/toolbox-testkit": "0.2.0",
|
"@add-ideas/toolbox-testkit": "0.2.2",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@testing-library/jest-dom": "^6.9.1",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
|
|||||||
@@ -40,5 +40,5 @@
|
|||||||
"repository": "https://git.add-ideas.de/zemion/onenote-tools",
|
"repository": "https://git.add-ideas.de/zemion/onenote-tools",
|
||||||
"license": "MPL-2.0 AND LGPL-2.1-only"
|
"license": "MPL-2.0 AND LGPL-2.1-only"
|
||||||
},
|
},
|
||||||
"version": "0.3.0"
|
"version": "0.3.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,27 @@ describe('Toolbox application shell', () => {
|
|||||||
name: 'Source for OneNote Tools on Gitea',
|
name: 'Source for OneNote Tools on Gitea',
|
||||||
})
|
})
|
||||||
).toHaveAttribute('href', 'https://git.add-ideas.de/zemion/onenote-tools');
|
).toHaveAttribute('href', 'https://git.add-ideas.de/zemion/onenote-tools');
|
||||||
|
expect(
|
||||||
|
Array.from(
|
||||||
|
screen.getByRole('group', { name: 'Toolbox controls' }).children,
|
||||||
|
(element) => element.getAttribute('aria-label')
|
||||||
|
)
|
||||||
|
).toEqual([
|
||||||
|
'Help',
|
||||||
|
'Source for OneNote Tools on Gitea',
|
||||||
|
'Apps',
|
||||||
|
'Personalize',
|
||||||
|
]);
|
||||||
|
expect(
|
||||||
|
Array.from(
|
||||||
|
document.querySelector('.toolbox-shell__bar')?.children ?? [],
|
||||||
|
(element) => element.className
|
||||||
|
)
|
||||||
|
).toEqual([
|
||||||
|
'toolbox-shell__brand',
|
||||||
|
'toolbox-shell__identity',
|
||||||
|
'toolbox-shell__controls',
|
||||||
|
]);
|
||||||
|
|
||||||
await user.click(screen.getByRole('button', { name: 'Help' }));
|
await user.click(screen.getByRole('button', { name: 'Help' }));
|
||||||
expect(
|
expect(
|
||||||
@@ -32,7 +53,16 @@ describe('Toolbox application shell', () => {
|
|||||||
const user = userEvent.setup();
|
const user = userEvent.setup();
|
||||||
const { container } = render(<App />);
|
const { container } = render(<App />);
|
||||||
|
|
||||||
await user.click(screen.getByText('Personalize'));
|
await user.click(screen.getByRole('button', { name: 'Personalize' }));
|
||||||
|
expect(
|
||||||
|
screen.getByRole('heading', { name: 'Personalize your toolbox' })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByRole('group', { name: 'Appearance' })
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.queryByRole('button', { name: 'Export JSON' })
|
||||||
|
).not.toBeInTheDocument();
|
||||||
await user.click(screen.getByRole('button', { name: 'Dark' }));
|
await user.click(screen.getByRole('button', { name: 'Dark' }));
|
||||||
|
|
||||||
expect(container.querySelector('.toolbox-shell')).toHaveAttribute(
|
expect(container.querySelector('.toolbox-shell')).toHaveAttribute(
|
||||||
|
|||||||
21
src/application-width.test.ts
Normal file
21
src/application-width.test.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import path from 'node:path';
|
||||||
|
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
describe('application width', () => {
|
||||||
|
it('uses the complete width supplied by the shared Toolbox shell', async () => {
|
||||||
|
const stylesheet = await readFile(
|
||||||
|
path.join(process.cwd(), 'src', 'styles.css'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
const applicationRules = Array.from(
|
||||||
|
stylesheet.matchAll(/\.application\s*\{([^}]*)\}/g),
|
||||||
|
(match) => match[1] ?? ''
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(applicationRules).not.toHaveLength(0);
|
||||||
|
expect(applicationRules.join('\n')).toMatch(/\bwidth:\s*100%;/);
|
||||||
|
expect(applicationRules.join('\n')).not.toMatch(/\bwidth:\s*min\(/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -106,7 +106,7 @@ body {
|
|||||||
.application {
|
.application {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 1.25rem;
|
gap: 1.25rem;
|
||||||
width: min(76rem, calc(100% - 2rem));
|
width: 100%;
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +801,6 @@ body {
|
|||||||
|
|
||||||
@media (max-width: 760px) {
|
@media (max-width: 760px) {
|
||||||
.application {
|
.application {
|
||||||
width: min(100% - 1rem, 76rem);
|
|
||||||
margin: 0.75rem auto;
|
margin: 0.75rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export const APP_VERSION = '0.3.0';
|
export const APP_VERSION = '0.3.3';
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ describe('release archive', () => {
|
|||||||
'react',
|
'react',
|
||||||
]);
|
]);
|
||||||
const text = bundle.toString('utf8');
|
const text = bundle.toString('utf8');
|
||||||
expect(text).toContain('@add-ideas/toolbox-contract@0.2.0');
|
expect(text).toContain('@add-ideas/toolbox-contract@0.2.2');
|
||||||
expect(text).toContain('@add-ideas/toolbox-shell-react@0.2.0');
|
expect(text).toContain('@add-ideas/toolbox-shell-react@0.2.2');
|
||||||
expect(text).toContain('react@');
|
expect(text).toContain('react@');
|
||||||
expect(createHash('sha256').update(bundle).digest('hex')).toMatch(
|
expect(createHash('sha256').update(bundle).digest('hex')).toMatch(
|
||||||
/^[a-f0-9]{64}$/
|
/^[a-f0-9]{64}$/
|
||||||
|
|||||||
Reference in New Issue
Block a user