Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f19b2528a | ||
|
|
1f11c39773 | ||
|
|
b6ccb5927a | ||
|
|
1d465ee318 | ||
|
|
3ab48b1cf5 | ||
|
|
de4ac978bd | ||
|
|
8df5faf4ef | ||
|
|
99a2035fdb | ||
|
|
a0d61728ea | ||
|
|
312bf6102c | ||
|
|
f4885b6f1c | ||
|
|
ca63a0979e | ||
|
|
1f266c3353 | ||
|
|
c7b2a70312 | ||
|
|
255133af4d | ||
|
|
db74531cd4 | ||
|
|
f36d8bfc78 | ||
|
|
3b31ace726 | ||
|
|
6badfef9da | ||
|
|
8c38dd73d8 | ||
|
|
b8682a852a | ||
|
|
8c17929151 | ||
|
|
bb92c9ec28 |
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,5 +1,53 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.7.2 (2020-09-06)
|
||||||
|
|
||||||
|
* update onesync documentation and do not recommend it as it breaks other apps | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f36d8bfc7848bb65ac0c641e318a689bf3816ccf)
|
||||||
|
* add reversibility for biometric disabling and do not recommend it | [commit](https://github.com/undergroundwires/privacy.sexy/commit/db74531cd4139615c6d595959217d3651f099019)
|
||||||
|
* fix bad highlighting of selected nodes when using keyboard navigation | [commit](https://github.com/undergroundwires/privacy.sexy/commit/255133af4dfae40171406648a3e2920f16d71cb3)
|
||||||
|
* add reversibility to removing bloatware | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c7b2a703128470a05f12c9c6e8002444def37ef8)
|
||||||
|
* fix indeterminate state being lost | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1f266c33535f72b69c65985bf2eff27cd2c5a104)
|
||||||
|
* fix wording in default text in text area | [commit](https://github.com/undergroundwires/privacy.sexy/commit/ca63a0979ef55d07d09d9443e5cea9aa888870a5)
|
||||||
|
* add best practice suggestion to come back | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f4885b6f1c82752f2143934e336d6d1b1af03015)
|
||||||
|
|
||||||
|
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.1...0.7.2)
|
||||||
|
|
||||||
|
## 0.7.1 (2020-09-04)
|
||||||
|
|
||||||
|
* fix some browsers (including firefox) downloading the script as a text file | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8c17929151f9c4fa5f48564492bbf400ced95eea)
|
||||||
|
* rename screenshot image file | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b8682a852a14ed6cf49986695d9510b840ac9d3d)
|
||||||
|
* fix new/changed script higlighting not working on production builds | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8c38dd73d8c7b77d8d341c0389f4d7229f9b97fd)
|
||||||
|
* refactor unused imports | [commit](https://github.com/undergroundwires/privacy.sexy/commit/6badfef9daace0c5de3fd33652a82bfe22261b11)
|
||||||
|
|
||||||
|
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.7.0...0.7.1)
|
||||||
|
|
||||||
|
## 0.7.0 (2020-09-02)
|
||||||
|
|
||||||
|
* [search] better (multilined) message when there are no results | [commit](https://github.com/undergroundwires/privacy.sexy/commit/ec15af01dd020b364c2174fe562fd66227c2320c)
|
||||||
|
* [search] added clear/close button | [commit](https://github.com/undergroundwires/privacy.sexy/commit/d6fa9a2a03c0ebe68b94f0b80cc52b4e200c9213)
|
||||||
|
* move script generation to /generation | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5df458739d076719e350ba194c4f3f772884fcdb)
|
||||||
|
* add auto-highlighting of selected/updated code | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b789250cb89e2130b08e1a927df8181cf945dfeb)
|
||||||
|
* prompt admin priviliges automatically | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f8ba5c46e4923d9c35f200f8a08aa6437f7c0ecc)
|
||||||
|
* add removal of ghost (default0) telemetry user | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c262681011f39b4412669b6cf233476f676ca550)
|
||||||
|
* add more windows defender tweaks, categorization and reversibility | [commit](https://github.com/undergroundwires/privacy.sexy/commit/1a34c7374ba56bafa0209bbb55c81b233bb419ed)
|
||||||
|
* fix NTP script documentation is on wrong place | [commit](https://github.com/undergroundwires/privacy.sexy/commit/3060ebf79cf242370433495cc3e1878b7581b202)
|
||||||
|
* updated dependencies to latest and audit fixes (#25) | [commit](https://github.com/undergroundwires/privacy.sexy/commit/c628aa9aef8ab7c815661d3c1711e7fbc65c69a2)
|
||||||
|
* categorize, fix and extend windows log files cleanup | [commit](https://github.com/undergroundwires/privacy.sexy/commit/594a14d6ca76cbd27a21877b8c373c1930589ca6)
|
||||||
|
* add more OneDrive cleanup scripts and categorize them | [commit](https://github.com/undergroundwires/privacy.sexy/commit/978d7d08638dd161082f239ed088b12302f29458)
|
||||||
|
* add disabling firefox telemetry | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f8b8b4c97ab734d5ba7370894b694993924388da)
|
||||||
|
* add disabling ccleaner telemetry | [commit](https://github.com/undergroundwires/privacy.sexy/commit/018b7e270f207aac926cb12f8069ebfcdce193ce)
|
||||||
|
* Add disabling of PowerShell 7+ telemetry (#29) | [commit](https://github.com/undergroundwires/privacy.sexy/commit/456e40bedf9afcc846f9b13f1ea144cef6115cf6)
|
||||||
|
* categorize, fix, make scripts reversible in "UI for privacy", "security improvements" and "configure browsers" | [commit](https://github.com/undergroundwires/privacy.sexy/commit/532915b95da9fecd6b981d91bf489359e4e53caa)
|
||||||
|
* fix "Configure Defender" being in wrong category #28 | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f709d6a566ed7846b677b383863deda9680a2a9c)
|
||||||
|
* do not hardcode capability versions and make them reversible | [commit](https://github.com/undergroundwires/privacy.sexy/commit/2afef4ea3d0d3d09aa1fa1eedba8493680bd8f10)
|
||||||
|
* exclude paint, wordpad and notepad from bloatware removal | [commit](https://github.com/undergroundwires/privacy.sexy/commit/d235dee95514a01745aef9479d07f88ffb4b40b8)
|
||||||
|
* add reversibility on category level | [commit](https://github.com/undergroundwires/privacy.sexy/commit/f51e8859eeb32c944126d692cfe03a0320c8b568)
|
||||||
|
* refactor unused imports & variables | [commit](https://github.com/undergroundwires/privacy.sexy/commit/a23d28f2cfa2d64d45460697cf5ee9d6b5920752)
|
||||||
|
* fix search (got broken in b789250) with tests and refactorings | [commit](https://github.com/undergroundwires/privacy.sexy/commit/8bbe6ebf750f1a1cbab493fb99b5ea91f4e21609)
|
||||||
|
* update the screenshot to show off highlighting | [commit](https://github.com/undergroundwires/privacy.sexy/commit/b4aacea2a3e0bbcf2d8a79ff67f51c0f19e888a6)
|
||||||
|
|
||||||
|
[compare](https://github.com/undergroundwires/privacy.sexy/compare/0.6.2...0.7.0)
|
||||||
|
|
||||||
## 0.6.2 (2020-08-16)
|
## 0.6.2 (2020-08-16)
|
||||||
|
|
||||||
* 🐛 fixed disabling error reporting for november 2019 update | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5967347b80976a519f6f4eb1972a62f3e600df2b)
|
* 🐛 fixed disabling error reporting for november 2019 update | [commit](https://github.com/undergroundwires/privacy.sexy/commit/5967347b80976a519f6f4eb1972a62f3e600df2b)
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
## Get started
|
## Get started
|
||||||
|
|
||||||
- Online version: [https://privacy.sexy](https://privacy.sexy)
|
- Online version: [https://privacy.sexy](https://privacy.sexy)
|
||||||
- or download latest desktop version for [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-Setup-0.6.2.exe), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-0.6.2.AppImage), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.6.2/privacy.sexy-0.6.2.dmg)
|
- or download latest desktop version for [Windows](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-Setup-0.7.2.exe), [Linux](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-0.7.2.AppImage), [macOS](https://github.com/undergroundwires/privacy.sexy/releases/download/0.7.2/privacy.sexy-0.7.2.dmg)
|
||||||
|
- 💡 Come back regularly to apply latest version for stronger privacy and security.
|
||||||
|
|
||||||
[](https://privacy.sexy)
|
[](https://privacy.sexy)
|
||||||
|
|
||||||
## Why
|
## Why
|
||||||
|
|
||||||
@@ -48,8 +49,8 @@
|
|||||||
- Development: `npm run serve` to compile & hot-reload for development.
|
- Development: `npm run serve` to compile & hot-reload for development.
|
||||||
- Production: `npm run build` to prepare files for distribution.
|
- Production: `npm run build` to prepare files for distribution.
|
||||||
- Or run using Docker:
|
- Or run using Docker:
|
||||||
1. Build: `docker build -t undergroundwires/privacy.sexy:0.6.2 .`
|
1. Build: `docker build -t undergroundwires/privacy.sexy:0.7.2 .`
|
||||||
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy-0.6.2 undergroundwires/privacy.sexy:0.6.2`
|
2. Run: `docker run -it -p 8080:80 --rm --name privacy.sexy-0.7.2 undergroundwires/privacy.sexy:0.7.2`
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "privacy.sexy",
|
"name": "privacy.sexy",
|
||||||
"version": "0.6.2",
|
"version": "0.7.2",
|
||||||
"author": "undergroundwires",
|
"author": "undergroundwires",
|
||||||
"description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆",
|
"description": "Enforce privacy & security best-practices on Windows, because privacy is sexy 🍑🍆",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ function parseCategoryChild(
|
|||||||
children.subScripts.push(script);
|
children.subScripts.push(script);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Child element is neither a category or a script.
|
throw new Error(`Child element is neither a category or a script.
|
||||||
Parent: ${parent.category}, element: ${categoryOrScript}`);
|
Parent: ${parent.category}, element: ${JSON.stringify(categoryOrScript)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,9 @@ function mayBeUniqueLine(codeLine: string): boolean {
|
|||||||
if (trimmed === ')' || trimmed === '(') { // "(" and ")" are used often in batch code
|
if (trimmed === ')' || trimmed === '(') { // "(" and ")" are used often in batch code
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (codeLine.startsWith(':: ') || codeLine.startsWith('REM ')) { // Is comment?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,18 @@
|
|||||||
import fileSaver from 'file-saver';
|
import fileSaver from 'file-saver';
|
||||||
|
|
||||||
export class SaveFileDialog {
|
export enum FileType {
|
||||||
public static saveText(text: string, fileName: string): void {
|
BatchFile,
|
||||||
this.saveBlob(text, 'text/plain;charset=utf-8', fileName);
|
|
||||||
}
|
}
|
||||||
|
export class SaveFileDialog {
|
||||||
|
public static saveFile(text: string, fileName: string, type: FileType): void {
|
||||||
|
const mimeType = this.mimeTypes.get(type);
|
||||||
|
this.saveBlob(text, mimeType, fileName);
|
||||||
|
}
|
||||||
|
private static readonly mimeTypes = new Map<FileType, string>([
|
||||||
|
// Some browsers (including firefox + IE) require right mime type
|
||||||
|
// otherwise they ignore extension and save the file as text.
|
||||||
|
[ FileType.BatchFile, 'application/bat' ], // https://en.wikipedia.org/wiki/Batch_file
|
||||||
|
]);
|
||||||
|
|
||||||
private static saveBlob(file: BlobPart, fileType: string, fileName: string): void {
|
private static saveBlob(file: BlobPart, fileType: string, fileName: string): void {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ declare module 'liquor-tree' {
|
|||||||
// https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
|
// https://github.com/amsik/liquor-tree/blob/master/src/lib/Node.js
|
||||||
export interface ILiquorTreeNodeState {
|
export interface ILiquorTreeNodeState {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
indeterminate: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILiquorTreeNode {
|
export interface ILiquorTreeNode {
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ export class LiquorTreeOptions implements ILiquorTreeOptions {
|
|||||||
public readonly checkbox = true;
|
public readonly checkbox = true;
|
||||||
public readonly checkOnSelect = true;
|
public readonly checkOnSelect = true;
|
||||||
/* For checkbox mode only. Children will have the same checked state as their parent.
|
/* For checkbox mode only. Children will have the same checked state as their parent.
|
||||||
|
⚠️ Setting this false, does not update indeterminate state of nodes.
|
||||||
This is false as it's handled manually to be able to batch select for performance + highlighting */
|
This is false as it's handled manually to be able to batch select for performance + highlighting */
|
||||||
public readonly autoCheckChildren = false;
|
public readonly autoCheckChildren = false;
|
||||||
public readonly parentSelect = false;
|
public readonly parentSelect = true;
|
||||||
public readonly keyboardNavigation = true;
|
public readonly keyboardNavigation = true;
|
||||||
public readonly filter = { // Wrap this in an arrow function as setting filter directly does not work JS APIs
|
public readonly filter = { // Wrap this in an arrow function as setting filter directly does not work JS APIs
|
||||||
emptyText: this.liquorTreeFilter.emptyText,
|
emptyText: this.liquorTreeFilter.emptyText,
|
||||||
|
|||||||
@@ -1,14 +1,37 @@
|
|||||||
import { ILiquorTreeNode } from 'liquor-tree';
|
import { ILiquorTreeNode, ILiquorTreeNodeState } from 'liquor-tree';
|
||||||
import { NodeType } from './../../Node/INode';
|
import { NodeType } from './../../Node/INode';
|
||||||
|
|
||||||
export function getNewCheckedState(
|
export function getNewState(
|
||||||
oldNode: ILiquorTreeNode,
|
node: ILiquorTreeNode,
|
||||||
|
selectedNodeIds: ReadonlyArray<string>): ILiquorTreeNodeState {
|
||||||
|
const checked = getNewCheckedState(node, selectedNodeIds);
|
||||||
|
const indeterminate = !checked && getNewIndeterminateState(node, selectedNodeIds);
|
||||||
|
return {
|
||||||
|
checked, indeterminate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNewIndeterminateState(
|
||||||
|
node: ILiquorTreeNode,
|
||||||
selectedNodeIds: ReadonlyArray<string>): boolean {
|
selectedNodeIds: ReadonlyArray<string>): boolean {
|
||||||
switch (oldNode.data.type) {
|
switch (node.data.type) {
|
||||||
case NodeType.Script:
|
case NodeType.Script:
|
||||||
return selectedNodeIds.some((id) => id === oldNode.id);
|
return false;
|
||||||
case NodeType.Category:
|
case NodeType.Category:
|
||||||
return parseAllSubScriptIds(oldNode).every((id) => selectedNodeIds.includes(id));
|
return parseAllSubScriptIds(node).some((id) => selectedNodeIds.includes(id));
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown node type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNewCheckedState(
|
||||||
|
node: ILiquorTreeNode,
|
||||||
|
selectedNodeIds: ReadonlyArray<string>): boolean {
|
||||||
|
switch (node.data.type) {
|
||||||
|
case NodeType.Script:
|
||||||
|
return selectedNodeIds.some((id) => id === node.id);
|
||||||
|
case NodeType.Category:
|
||||||
|
return parseAllSubScriptIds(node).every((id) => selectedNodeIds.includes(id));
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown node type');
|
throw new Error('Unknown node type');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function toNewLiquorTreeNode(node: INode): ILiquorTreeNewNode {
|
|||||||
text: node.text,
|
text: node.text,
|
||||||
state: {
|
state: {
|
||||||
checked: false,
|
checked: false,
|
||||||
|
indeterminate: false,
|
||||||
},
|
},
|
||||||
children: convertChildren(node.children, toNewLiquorTreeNode),
|
children: convertChildren(node.children, toNewLiquorTreeNode),
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
import { StatefulVue } from '@/presentation/StatefulVue';
|
import { StatefulVue } from '@/presentation/StatefulVue';
|
||||||
import { INode } from './INode';
|
import { INode } from './INode';
|
||||||
import { SelectedScript } from '@/application/State/Selection/SelectedScript';
|
import { SelectedScript } from '@/application/State/Selection/SelectedScript';
|
||||||
import { IApplicationState } from '@/application/State/IApplicationState';
|
|
||||||
import { getCategoryId, getScriptId } from './../../ScriptNodeParser';
|
|
||||||
import { getReverter } from './Reverter/ReverterFactory';
|
import { getReverter } from './Reverter/ReverterFactory';
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|||||||
@@ -18,14 +18,15 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||||
import LiquorTree, { ILiquorTreeNewNode, ILiquorTreeExistingNode, ILiquorTree } from 'liquor-tree';
|
import LiquorTree from 'liquor-tree';
|
||||||
import Node from './Node/Node.vue';
|
import Node from './Node/Node.vue';
|
||||||
import { INode } from './Node/INode';
|
import { INode } from './Node/INode';
|
||||||
import { convertExistingToNode, toNewLiquorTreeNode } from './LiquorTree/NodeWrapper/NodeTranslator';
|
import { convertExistingToNode, toNewLiquorTreeNode } from './LiquorTree/NodeWrapper/NodeTranslator';
|
||||||
import { INodeSelectedEvent } from './/INodeSelectedEvent';
|
import { INodeSelectedEvent } from './/INodeSelectedEvent';
|
||||||
import { getNewCheckedState } from './LiquorTree/NodeWrapper/NodeStateUpdater';
|
import { getNewState } from './LiquorTree/NodeWrapper/NodeStateUpdater';
|
||||||
import { LiquorTreeOptions } from './LiquorTree/LiquorTreeOptions';
|
import { LiquorTreeOptions } from './LiquorTree/LiquorTreeOptions';
|
||||||
import { FilterPredicate, NodePredicateFilter } from './LiquorTree/NodeWrapper/NodePredicateFilter';
|
import { FilterPredicate, NodePredicateFilter } from './LiquorTree/NodeWrapper/NodePredicateFilter';
|
||||||
|
import { ILiquorTreeNewNode, ILiquorTreeExistingNode, ILiquorTree, ILiquorTreeNode, ILiquorTreeNodeState } from 'liquor-tree';
|
||||||
|
|
||||||
/** Wrapper for Liquor Tree, reveals only abstracted INode for communication */
|
/** Wrapper for Liquor Tree, reveals only abstracted INode for communication */
|
||||||
@Component({
|
@Component({
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
const initialNodes = this.initialNodes.map((node) => toNewLiquorTreeNode(node));
|
const initialNodes = this.initialNodes.map((node) => toNewLiquorTreeNode(node));
|
||||||
if (this.selectedNodeIds) {
|
if (this.selectedNodeIds) {
|
||||||
recurseDown(initialNodes,
|
recurseDown(initialNodes,
|
||||||
(node) => node.state.checked = getNewCheckedState(node, this.selectedNodeIds));
|
(node) => node.state = updateState(node.state, node, this.selectedNodeIds));
|
||||||
}
|
}
|
||||||
this.initialLiquourTreeNodes = initialNodes;
|
this.initialLiquourTreeNodes = initialNodes;
|
||||||
} else {
|
} else {
|
||||||
@@ -82,11 +83,11 @@
|
|||||||
@Watch('selectedNodeIds')
|
@Watch('selectedNodeIds')
|
||||||
public setSelectedStatusAsync(selectedNodeIds: ReadonlyArray<string>) {
|
public setSelectedStatusAsync(selectedNodeIds: ReadonlyArray<string>) {
|
||||||
if (!selectedNodeIds) {
|
if (!selectedNodeIds) {
|
||||||
throw new Error('Selected nodes are undefined');
|
throw new Error('SelectedrecurseDown nodes are undefined');
|
||||||
}
|
}
|
||||||
this.getLiquorTreeApi().recurseDown((node) => {
|
this.getLiquorTreeApi().recurseDown(
|
||||||
node.states.checked = getNewCheckedState(node, selectedNodeIds);
|
(node) => node.states = updateState(node.states, node, selectedNodeIds),
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getLiquorTreeApi(): ILiquorTree {
|
private getLiquorTreeApi(): ILiquorTree {
|
||||||
@@ -97,6 +98,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateState(
|
||||||
|
old: ILiquorTreeNodeState,
|
||||||
|
node: ILiquorTreeNode,
|
||||||
|
selectedNodeIds: ReadonlyArray<string>): ILiquorTreeNodeState {
|
||||||
|
return {...old, ...getNewState(node, selectedNodeIds)};
|
||||||
|
}
|
||||||
|
|
||||||
function recurseDown(
|
function recurseDown(
|
||||||
nodes: ReadonlyArray<ILiquorTreeNewNode>,
|
nodes: ReadonlyArray<ILiquorTreeNewNode>,
|
||||||
handler: (node: ILiquorTreeNewNode) => void) {
|
handler: (node: ILiquorTreeNewNode) => void) {
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ const NothingChosenCode =
|
|||||||
.appendCommentLine('-- 🤔 How to use')
|
.appendCommentLine('-- 🤔 How to use')
|
||||||
.appendCommentLine(' 📙 Start by exploring different categories and choosing different tweaks.')
|
.appendCommentLine(' 📙 Start by exploring different categories and choosing different tweaks.')
|
||||||
.appendCommentLine(' 📙 You can select "Recommended" on the top to select "safer" tweaks. Always double check!')
|
.appendCommentLine(' 📙 You can select "Recommended" on the top to select "safer" tweaks. Always double check!')
|
||||||
.appendCommentLine(' 📙 After you choose any tweak, you can download & copy to execute your script.')
|
.appendCommentLine(' 📙 After you choose any tweak, you can download or copy to execute your script.')
|
||||||
|
.appendCommentLine(' 📙 Come back regularly to apply latest version for stronger privacy and security.')
|
||||||
.appendLine()
|
.appendLine()
|
||||||
.appendCommentLine('-- 🧐 Why privacy.sexy')
|
.appendCommentLine('-- 🧐 Why privacy.sexy')
|
||||||
.appendCommentLine(' ✔️ Rich tweak pool to harden security & privacy of the OS and other softwares on it.')
|
.appendCommentLine(' ✔️ Rich tweak pool to harden security & privacy of the OS and other softwares on it.')
|
||||||
@@ -114,7 +115,7 @@ function initializeEditor(theme: string, editorId: string): ace.Ace.Editor {
|
|||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
&__highlight {
|
&__highlight {
|
||||||
background-color:$accent;
|
background-color:$accent;
|
||||||
opacity: 20%;
|
opacity: 0.2; // having procent fails in production (minified) build
|
||||||
position:absolute;
|
position:absolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component } from 'vue-property-decorator';
|
import { Component } from 'vue-property-decorator';
|
||||||
import { StatefulVue } from './StatefulVue';
|
import { StatefulVue } from './StatefulVue';
|
||||||
import { SaveFileDialog } from './../infrastructure/SaveFileDialog';
|
import { SaveFileDialog, FileType } from './../infrastructure/SaveFileDialog';
|
||||||
import { Clipboard } from './../infrastructure/Clipboard';
|
import { Clipboard } from './../infrastructure/Clipboard';
|
||||||
import IconButton from './IconButton.vue';
|
import IconButton from './IconButton.vue';
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export default class TheCodeButtons extends StatefulVue {
|
|||||||
|
|
||||||
public async saveCodeAsync() {
|
public async saveCodeAsync() {
|
||||||
const state = await this.getCurrentStateAsync();
|
const state = await this.getCurrentStateAsync();
|
||||||
SaveFileDialog.saveText(state.code.current, 'privacy-script.bat');
|
SaveFileDialog.saveFile(state.code.current, 'privacy-script.bat', FileType.BatchFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,37 +2,27 @@
|
|||||||
@import "@/presentation/styles/colors.scss";
|
@import "@/presentation/styles/colors.scss";
|
||||||
|
|
||||||
.tree {
|
.tree {
|
||||||
background-color: $slate;
|
background: $slate;
|
||||||
}
|
&-node {
|
||||||
|
white-space: normal !important;
|
||||||
.tree-node > .tree-content > .tree-anchor > span {
|
> .tree-content {
|
||||||
color: $white !important;
|
> .tree-anchor > span {
|
||||||
|
color: $white;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: $light-gray;
|
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
&:hover {
|
||||||
.tree-node {
|
|
||||||
white-space: normal !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-arrow.has-child {
|
|
||||||
&.rtl:after, &:after {
|
|
||||||
border-color: $white !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-node.selected > .tree-content {
|
|
||||||
> .tree-anchor > span {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-content:hover {
|
|
||||||
background: $dark-gray !important;
|
background: $dark-gray !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.tree-checkbox {
|
&.selected { // When using keyboard navigation it higlights current item and its child items
|
||||||
|
background: $gray;
|
||||||
|
.tree-text {
|
||||||
|
color: $black !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-checkbox {
|
||||||
&.checked {
|
&.checked {
|
||||||
background: $accent !important;
|
background: $accent !important;
|
||||||
}
|
}
|
||||||
@@ -41,3 +31,11 @@
|
|||||||
}
|
}
|
||||||
background: $dark-slate !important;
|
background: $dark-slate !important;
|
||||||
}
|
}
|
||||||
|
&-arrow {
|
||||||
|
&.has-child {
|
||||||
|
&.rtl:after, &:after {
|
||||||
|
border-color: $white !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,31 +2,32 @@ import 'mocha';
|
|||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { ILiquorTreeNode } from 'liquor-tree';
|
import { ILiquorTreeNode } from 'liquor-tree';
|
||||||
import { NodeType } from '@/presentation/Scripts/ScriptsTree/SelectableTree/Node/INode';
|
import { NodeType } from '@/presentation/Scripts/ScriptsTree/SelectableTree/Node/INode';
|
||||||
import { getNewCheckedState } from '@/presentation/Scripts/ScriptsTree/SelectableTree/LiquorTree/NodeWrapper/NodeStateUpdater';
|
import { getNewState } from '@/presentation/Scripts/ScriptsTree/SelectableTree/LiquorTree/NodeWrapper/NodeStateUpdater';
|
||||||
|
|
||||||
describe('getNewCheckedState', () => {
|
describe('getNewState', () => {
|
||||||
|
describe('checked', () => {
|
||||||
describe('script node', () => {
|
describe('script node', () => {
|
||||||
it('state is true when selected', () => {
|
it('true when selected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const node = getScriptNode();
|
const node = getScriptNode();
|
||||||
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
|
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
|
||||||
// act
|
// act
|
||||||
const actual = getNewCheckedState(node, selectedScriptNodeIds);
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
// assert
|
// assert
|
||||||
expect(actual).to.equal(true);
|
expect(state.checked).to.equal(true);
|
||||||
});
|
});
|
||||||
it('state is false when unselected', () => {
|
it('false when unselected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const node = getScriptNode();
|
const node = getScriptNode();
|
||||||
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
||||||
// act
|
// act
|
||||||
const actual = getNewCheckedState(node, selectedScriptNodeIds);
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
// assert
|
// assert
|
||||||
expect(actual).to.equal(false);
|
expect(state.checked).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('category node', () => {
|
describe('category node', () => {
|
||||||
it('state is true when every child selected', () => {
|
it('true when every child selected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const node = {
|
const node = {
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -44,11 +45,11 @@ describe('getNewCheckedState', () => {
|
|||||||
};
|
};
|
||||||
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
||||||
// act
|
// act
|
||||||
const actual = getNewCheckedState(node, selectedScriptNodeIds);
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
// assert
|
// assert
|
||||||
expect(actual).to.equal(true);
|
expect(state.checked).to.equal(true);
|
||||||
});
|
});
|
||||||
it('state is false when none of the children is selected', () => {
|
it('false when none of the children is selected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const node = {
|
const node = {
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -66,11 +67,11 @@ describe('getNewCheckedState', () => {
|
|||||||
};
|
};
|
||||||
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
|
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
|
||||||
// act
|
// act
|
||||||
const actual = getNewCheckedState(node, selectedScriptNodeIds);
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
// assert
|
// assert
|
||||||
expect(actual).to.equal(false);
|
expect(state.checked).to.equal(false);
|
||||||
});
|
});
|
||||||
it('state is false when some of the children is selected', () => {
|
it('false when some of the children is selected', () => {
|
||||||
// arrange
|
// arrange
|
||||||
const node = {
|
const node = {
|
||||||
id: '1',
|
id: '1',
|
||||||
@@ -90,9 +91,100 @@ describe('getNewCheckedState', () => {
|
|||||||
};
|
};
|
||||||
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ];
|
const selectedScriptNodeIds = [ 'a', 'c', 'unrelated' ];
|
||||||
// act
|
// act
|
||||||
const actual = getNewCheckedState(node, selectedScriptNodeIds);
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
// assert
|
// assert
|
||||||
expect(actual).to.equal(false);
|
expect(state.checked).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('indeterminate', () => {
|
||||||
|
describe('script node', () => {
|
||||||
|
it('false when selected', () => {
|
||||||
|
// arrange
|
||||||
|
const node = getScriptNode();
|
||||||
|
const selectedScriptNodeIds = [ 'a', 'b', node.id, 'c' ];
|
||||||
|
// act
|
||||||
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
|
// assert
|
||||||
|
expect(state.indeterminate).to.equal(false);
|
||||||
|
});
|
||||||
|
it('false when not selected', () => {
|
||||||
|
// arrange
|
||||||
|
const node = getScriptNode();
|
||||||
|
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
||||||
|
// act
|
||||||
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
|
// assert
|
||||||
|
expect(state.indeterminate).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('category node', () => {
|
||||||
|
it('false when all children are selected', () => {
|
||||||
|
// arrange
|
||||||
|
const node = {
|
||||||
|
id: '1',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [
|
||||||
|
{ id: '2',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('a'), getScriptNode('b') ],
|
||||||
|
},
|
||||||
|
{ id: '3',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('c') ],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const selectedScriptNodeIds = [ 'a', 'b', 'c' ];
|
||||||
|
// act
|
||||||
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
|
// assert
|
||||||
|
expect(state.indeterminate).to.equal(false);
|
||||||
|
});
|
||||||
|
it('true when all some are selected', () => {
|
||||||
|
// arrange
|
||||||
|
const node = {
|
||||||
|
id: '1',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [
|
||||||
|
{ id: '2',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('a'), getScriptNode('b') ],
|
||||||
|
},
|
||||||
|
{ id: '3',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('c') ],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const selectedScriptNodeIds = [ 'a' ];
|
||||||
|
// act
|
||||||
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
|
// assert
|
||||||
|
expect(state.indeterminate).to.equal(true);
|
||||||
|
});
|
||||||
|
it('false when no children are selected', () => {
|
||||||
|
// arrange
|
||||||
|
const node = {
|
||||||
|
id: '1',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [
|
||||||
|
{ id: '2',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('a'), getScriptNode('b') ],
|
||||||
|
},
|
||||||
|
{ id: '3',
|
||||||
|
data: { type: NodeType.Category, documentationUrls: [], isReversible: false },
|
||||||
|
children: [ getScriptNode('c') ],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const selectedScriptNodeIds = [ 'none', 'of', 'them', 'are', 'selected' ];
|
||||||
|
// act
|
||||||
|
const state = getNewState(node, selectedScriptNodeIds);
|
||||||
|
// assert
|
||||||
|
expect(state.indeterminate).to.equal(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ function getNewNode(): ILiquorTreeNewNode {
|
|||||||
const base = getNode();
|
const base = getNode();
|
||||||
const commonState = {
|
const commonState = {
|
||||||
checked: false,
|
checked: false,
|
||||||
|
indeterminate: false,
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
id: base.id,
|
id: base.id,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ describe('ScriptReverter', () => {
|
|||||||
selection: [ new SelectedScript(script, true)], revert: true, expectRevert: true,
|
selection: [ new SelectedScript(script, true)], revert: true, expectRevert: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'keeps revert state deselected when already selected wtih non revert state',
|
name: 'keeps revert state deselected when already selected with non revert state',
|
||||||
selection: [ new SelectedScript(script, false)], revert: false, expectRevert: false,
|
selection: [ new SelectedScript(script, false)], revert: false, expectRevert: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user