Skip to content

Commit

Permalink
Merge pull request #3207 from nextcloud/fix/eslint/ts-tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
provokateurin authored Sep 13, 2024
2 parents 691b04c + d95a2da commit 0cb2265
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 116 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"build": "NODE_ENV=production webpack --progress --config webpack.js",
"dev": "NODE_ENV=development webpack --progress --config webpack.js",
"watch": "NODE_ENV=development webpack --progress --watch --config webpack.js",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --ext .js,.vue src --fix",
"lint": "eslint --ext .js,.vue,.tsx,.ts src",
"lint:fix": "eslint --ext .js,.vue,.tsx,.ts src --fix",
"stylelint": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue",
"stylelint:fix": "stylelint css/*.css css/*.scss src/**/*.scss src/**/*.vue --fix",
"cypress": "npm run cypress:e2e",
Expand Down
23 changes: 7 additions & 16 deletions src/settings/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import * as React from 'react'
import { Component, FormEvent } from 'react'

import { Api, Circle, Folder, Group, OCSGroup, OCSUser } from './Api'
import { Api, Circle, Folder, Group, ManageRuleProps } from './Api'
import { FolderGroups } from './FolderGroups'
import { QuotaSelect } from './QuotaSelect'
import './App.scss'
Expand Down Expand Up @@ -45,7 +45,7 @@ export interface AppState {
checkAppsInstalled: boolean;
}

export class App extends Component<{}, AppState> implements OC.Plugin<OC.Search.Core> {
export class App extends Component<unknown, AppState> implements OC.Plugin<OC.Search.Core> {

api = new Api()

Expand Down Expand Up @@ -367,23 +367,14 @@ export class App extends Component<{}, AppState> implements OC.Plugin<OC.Search.
interface ManageAclSelectProps {
folder: Folder;
onChange: (type: string, id: string, manageAcl: boolean) => void;
onSearch: (name: string) => Thenable<{ groups: OCSGroup[]; users: OCSUser[]; }>;
onSearch: (name: string) => Thenable<{ groups: ManageRuleProps[]; users: ManageRuleProps[]; }>;
}

/**
*
* @param root0
* @param root0.onChange
* @param root0.onSearch
* @param root0.folder
*/
// eslint-disable-next-line jsdoc/require-jsdoc
function ManageAclSelect({ onChange, onSearch, folder }: ManageAclSelectProps) {
const handleSearch = (inputValue: string) => {
return new Promise<any>(resolve => {
onSearch(inputValue).then((result) => {
resolve([...result.groups, ...result.users])
})
})
const handleSearch = async (inputValue: string) => {
const result = await onSearch(inputValue)
return [...result.groups, ...result.users]
}

const typeLabel = (item) => {
Expand Down
56 changes: 29 additions & 27 deletions src/settings/FolderGroups.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import './FolderGroups.scss'
import { Circle, Group } from './Api'
import { loadState } from '@nextcloud/initial-state'

// eslint-disable-next-line jsdoc/require-jsdoc
function hasPermissions(value: number, check: number): boolean {
return (value & check) === check
}
Expand All @@ -21,11 +22,12 @@ export interface FolderGroupsProps {
onAddGroup: (name: string) => void;
removeGroup: (name: string) => void;
edit: boolean;
showEdit: (event: SyntheticEvent<any>) => void;
showEdit: (event: SyntheticEvent<unknown>) => void;
onSetPermissions: (name: string, permissions: number) => void;
}

export function FolderGroups({groups, allGroups = [], allCircles = [], onAddGroup, removeGroup, edit, showEdit, onSetPermissions}: FolderGroupsProps) {
// eslint-disable-next-line jsdoc/require-jsdoc
export function FolderGroups({ groups, allGroups = [], allCircles = [], onAddGroup, removeGroup, edit, showEdit, onSetPermissions }: FolderGroupsProps) {
const isCirclesEnabled = loadState('groupfolders', 'isCirclesEnabled', false)
const groupHeader = isCirclesEnabled
? t('groupfolders', 'Group or team')
Expand All @@ -44,7 +46,7 @@ export function FolderGroups({groups, allGroups = [], allCircles = [], onAddGrou
const setPermissions = (change: number, groupId: string): void => {
const newPermissions = groups[groupId] ^ change
onSetPermissions(groupId, newPermissions)
};
}

const rows = Object.keys(groups).map((groupId, index) => {
const permissions = groups[groupId]
Expand All @@ -71,28 +73,27 @@ export function FolderGroups({groups, allGroups = [], allCircles = [], onAddGrou
</tr>
})


return <table className="group-edit"
onClick={event => event.stopPropagation()}>
<thead>
<tr>
<th>{groupHeader}</th>
<th>Write</th>
<th>Share</th>
<th>Delete</th>
<th/>
</tr>
<tr>
<th>{groupHeader}</th>
<th>Write</th>
<th>Share</th>
<th>Delete</th>
<th/>
</tr>
</thead>
<tbody>
{rows}
<tr>
<td colSpan={5}>
<AdminGroupSelect
allGroups={allGroups.filter(i => !groups[i.gid])}
allCircles={allCircles.filter(i => !groups[i.singleId])}
onChange={onAddGroup}/>
</td>
</tr>
{rows}
<tr>
<td colSpan={5}>
<AdminGroupSelect
allGroups={allGroups.filter(i => !groups[i.gid])}
allCircles={allCircles.filter(i => !groups[i.singleId])}
onChange={onAddGroup}/>
</td>
</tr>
</tbody>
</table>
} else {
Expand All @@ -115,7 +116,8 @@ interface CircleGroupSelectProps {
onChange: (name: string) => void;
}

function AdminGroupSelect({allGroups, allCircles, onChange}: CircleGroupSelectProps) {
// eslint-disable-next-line jsdoc/require-jsdoc
function AdminGroupSelect({ allGroups, allCircles, onChange }: CircleGroupSelectProps) {
const isCirclesEnabled = loadState('groupfolders', 'isCirclesEnabled', false)
const emptyGroups = isCirclesEnabled
? t('groupfolders', 'No other groups or teams available')
Expand All @@ -129,13 +131,13 @@ function AdminGroupSelect({allGroups, allCircles, onChange}: CircleGroupSelectPr
const groups = allGroups.map(group => {
return {
value: group.gid,
label: group.displayName
label: group.displayName,
}
})
const circles = allCircles.map(circle => {
return {
value: circle.singleId,
label: t('groupfolders', '{displayName} (team)', {...circle})
label: t('groupfolders', '{displayName} (team)', { ...circle }),
}
})
const options = [...groups, ...circles]
Expand All @@ -154,7 +156,7 @@ function AdminGroupSelect({allGroups, allCircles, onChange}: CircleGroupSelectPr
input: (provided) => ({
...provided,
height: 30,
color: 'var(--color-primary-element-text)'
color: 'var(--color-primary-element-text)',
}),
control: (provided) => ({
...provided,
Expand All @@ -163,12 +165,12 @@ function AdminGroupSelect({allGroups, allCircles, onChange}: CircleGroupSelectPr
menu: (provided) => ({
...provided,
backgroundColor: 'var(--color-main-background)',
borderColor: '#888'
borderColor: '#888',
}),
option: (provided, state) => ({
...provided,
backgroundColor: state.isFocused ? 'var(--color-background-dark)' : 'transparent'
})
backgroundColor: state.isFocused ? 'var(--color-background-dark)' : 'transparent',
}),
}}
/>
}
30 changes: 15 additions & 15 deletions src/settings/Nextcloud.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ declare namespace OC {

interface Plugin<T> {
name?: string;
attach: (instance: T, options: any) => void;
detach?: (instance: T, options: any) => void;
attach: (instance: T, options: unknown) => void;
detach?: (instance: T, options: unknown) => void;
}

namespace Plugins {
function register(scope: string, plugin: OC.Plugin<any>): void;
function attach(targetName: string, targetObject: any, options: any): void;
function detach(targetName: string, targetObject: any, options: any): void;
function getPlugins(): OC.Plugin<any>[];
function register(scope: string, plugin: OC.Plugin<unknown>): void;
function attach(targetName: string, targetObject: unknown, options: unknown): void;
function detach(targetName: string, targetObject: unknown, options: unknown): void;
function getPlugins(): OC.Plugin<unknown>[];
}

namespace Search {
Expand All @@ -52,12 +52,12 @@ declare namespace OC {

function filePath(app: string, type: string, file: string): string;

const PERMISSION_CREATE = 4;
const PERMISSION_READ = 1;
const PERMISSION_UPDATE = 2;
const PERMISSION_DELETE = 8;
const PERMISSION_SHARE = 16;
const PERMISSION_ALL = 31;
const PERMISSION_CREATE = 4
const PERMISSION_READ = 1
const PERMISSION_UPDATE = 2
const PERMISSION_DELETE = 8
const PERMISSION_SHARE = 16
const PERMISSION_ALL = 31

const config: {
blacklist_files_regex: string;
Expand All @@ -66,11 +66,11 @@ declare namespace OC {
modRewriteWorking: boolean;
session_keepalive: boolean;
session_lifetime: boolean;
"sharing.maxAutocompleteResults": number;
"sharing.minSearchStringLength": number;
'sharing.maxAutocompleteResults': number;
'sharing.minSearchStringLength': number;
version: string;
versionString: string;
};
}
}

declare function t(app: string, string: string, vars?: { [key: string]: string }, count?: number, options?: EscapeOptions): string;
78 changes: 37 additions & 41 deletions src/settings/QuotaSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import * as React from 'react';
import {Component} from 'react';

import './EditSelect.scss';
import * as React from 'react'
import { Component } from 'react'
import { formatFileSize, parseFileSize } from '@nextcloud/files'
import './EditSelect.scss'

export interface QuotaSelectProps {
options: { [name: string]: number };
Expand All @@ -21,84 +21,79 @@ export interface QuotaSelectState {
}

export class QuotaSelect extends Component<QuotaSelectProps, QuotaSelectState> {

state: QuotaSelectState = {
options: {},
isEditing: false,
isValidInput: true
};
isValidInput: true,
}

constructor(props) {
super(props);
this.state.options = props.options;
super(props)
this.state.options = props.options
if (props.value >= 0) {
const valueText = OC.Util.humanFileSize(props.value);
this.state.options[valueText] = props.value;
const valueText = formatFileSize(props.value)
this.state.options[valueText] = props.value
}
}

onSelect = event => {
const value = event.target.value;
const value = event.target.value
if (value === 'other') {
this.setState({isEditing: true});
this.setState({ isEditing: true })
} else {
this.props.onChange(value);
this.props.onChange(value)
}
};
}

onEditedValue = (value) => {
const size = OC.Util.computerFileSize(value);
const size = parseFileSize(value)
if (!size) {
this.setState({isValidInput: false});
this.setState({ isValidInput: false })
} else {
this.setState({isValidInput: true, isEditing: false});
const options = this.state.options;
options[OC.Util.humanFileSize(size)] = size;
this.props.onChange(size);
this.setState({ isValidInput: true, isEditing: false })
const options = this.state.options
options[formatFileSize(size)] = size
this.props.onChange(size)
}
};
}

getUsedPercentage() {
if (this.props.value >= 0) {
return Math.min((this.props.size / this.props.value) * 100, 100);
return Math.min((this.props.size / this.props.value) * 100, 100)
} else {
const usedInGB = this.props.size / (10 * Math.pow(2, 30));
const usedInGB = this.props.size / (10 * Math.pow(2, 30))
// asymptotic curve approaching 50% at 10GB to visualize used stace with infinite quota
return 95 * (1 - (1 / (usedInGB + 1)));
return 95 * (1 - (1 / (usedInGB + 1)))
}
}

render() {
if (this.state.isEditing) {
return <input
onBlur={() => {
this.setState({isEditing: false})
this.setState({ isEditing: false })
}}
onKeyPress={(e) => {
(e.key === 'Enter' ? this.onEditedValue((e.target as HTMLInputElement).value) : null)
if (e.key === 'Enter') {
this.onEditedValue((e.target as HTMLInputElement).value)
}
}}
className={'editselect-input' + (this.state.isValidInput ? '' : ' error')}
autoFocus={true}/>
} else {
const usedPercentage = this.getUsedPercentage();
const humanSize = OC.Util.humanFileSize(this.props.size);
const usedPercentage = this.getUsedPercentage()
const humanSize = formatFileSize(this.props.size)
const options = Object.keys(this.state.options).map((key) => <option
value={this.state.options[key]} key={key}>{key}</option>);
value={this.state.options[key]} key={key}>{key}</option>)

return <div className="quotabar-holder">
<div className="quotabar"
style={{width: usedPercentage + '%'}}/>
style={{ width: usedPercentage + '%' }}/>
<select className="editselect"
onChange={this.onSelect}
ref={(ref) => {
ref && $(ref).tooltip({
title: t('settings', '{size} used', {size: humanSize}, 0, {escape: false}).replace('&lt;', '<'),
delay: {
show: 100,
hide: 0
}
});
}}
value={this.props.value}>
onChange={this.onSelect}
title={t('settings', '{size} used', { size: humanSize }, 0, { escape: false }).replace('&lt;', '<')}
value={this.props.value}>
{options}
<option value="other">
{t('groupfolders', 'Other …')}
Expand All @@ -107,4 +102,5 @@ export class QuotaSelect extends Component<QuotaSelectProps, QuotaSelectState> {
</div>
}
}

}
Loading

0 comments on commit 0cb2265

Please sign in to comment.