mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Linting
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState } from "react";
|
||||||
import { Form, Col } from 'react-bootstrap';
|
import { Form, Col } from 'react-bootstrap';
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
@@ -22,6 +22,29 @@ function convertTime(logEntry: GQL.LogEntryDataFragment) {
|
|||||||
return dateStr;
|
return dateStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function levelClass(level : string) {
|
||||||
|
return level.toLowerCase().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILogElementProps {
|
||||||
|
logEntry : LogEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
const LogElement: React.FC<ILogElementProps> = ({ logEntry }) => {
|
||||||
|
// pad to maximum length of level enum
|
||||||
|
var level = logEntry.level.padEnd(GQL.LogLevel.Progress.length);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span>{logEntry.time}</span>
|
||||||
|
<span className={levelClass(logEntry.level)}>{level}</span>
|
||||||
|
<span>{logEntry.message}</span>
|
||||||
|
<br/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class LogEntry {
|
class LogEntry {
|
||||||
public time: string;
|
public time: string;
|
||||||
public level: string;
|
public level: string;
|
||||||
@@ -40,120 +63,29 @@ class LogEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maximum number of log entries to display. Subsequent entries will truncate
|
||||||
|
// the list, dropping off the oldest entries first.
|
||||||
|
const MAX_LOG_ENTRIES = 200;
|
||||||
|
const logLevels = ["Debug", "Info", "Warning", "Error"];
|
||||||
|
|
||||||
export const SettingsLogsPanel: React.FC = () => {
|
export const SettingsLogsPanel: React.FC = () => {
|
||||||
const { data, error } = StashService.useLoggingSubscribe();
|
const { data, error } = StashService.useLoggingSubscribe();
|
||||||
const { data: existingData } = StashService.useLogs();
|
const { data: existingData } = StashService.useLogs();
|
||||||
|
|
||||||
const logEntries = useRef<LogEntry[]>([]);
|
|
||||||
const [logLevel, setLogLevel] = useState<string>("Info");
|
const [logLevel, setLogLevel] = useState<string>("Info");
|
||||||
const [filteredLogEntries, setFilteredLogEntries] = useState<LogEntry[]>([]);
|
|
||||||
const lastUpdate = useRef<number>(0);
|
|
||||||
const updateTimeout = useRef<NodeJS.Timeout>();
|
|
||||||
|
|
||||||
// maximum number of log entries to display. Subsequent entries will truncate
|
const oldData = (existingData?.logs ?? []).map(e => new LogEntry(e));
|
||||||
// the list, dropping off the oldest entries first.
|
const newData = (data?.loggingSubscribe ?? []).map(e => new LogEntry(e));
|
||||||
const MAX_LOG_ENTRIES = 200;
|
|
||||||
|
|
||||||
function truncateLogEntries(entries : LogEntry[]) {
|
const filteredLogEntries = [...newData.reverse(), ...oldData]
|
||||||
entries.length = Math.min(entries.length, MAX_LOG_ENTRIES);
|
.filter(filterByLogLevel).slice(0, MAX_LOG_ENTRIES);
|
||||||
}
|
|
||||||
|
|
||||||
function prependLogEntries(toPrepend : LogEntry[]) {
|
const maybeRenderError = error
|
||||||
var newLogEntries = toPrepend.concat(logEntries.current);
|
? <div className={"error"}>Error connecting to log server: {error.message}</div>
|
||||||
truncateLogEntries(newLogEntries);
|
: '';
|
||||||
logEntries.current = newLogEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
function appendLogEntries(toAppend : LogEntry[]) {
|
|
||||||
var newLogEntries = logEntries.current.concat(toAppend);
|
|
||||||
truncateLogEntries(newLogEntries);
|
|
||||||
logEntries.current = newLogEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!data) { return; }
|
|
||||||
|
|
||||||
// append data to the logEntries
|
|
||||||
var convertedData = data.loggingSubscribe.map(convertLogEntry);
|
|
||||||
|
|
||||||
// filter subscribed data as it comes in, otherwise we'll end up
|
|
||||||
// truncating stuff that wasn't filtered out
|
|
||||||
convertedData = convertedData.filter(filterByLogLevel)
|
|
||||||
|
|
||||||
// put newest entries at the top
|
|
||||||
convertedData.reverse();
|
|
||||||
prependLogEntries(convertedData);
|
|
||||||
|
|
||||||
updateFilteredEntries();
|
|
||||||
}, [data]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!existingData || !existingData.logs) { return; }
|
|
||||||
|
|
||||||
var convertedData = existingData.logs.map(convertLogEntry);
|
|
||||||
appendLogEntries(convertedData);
|
|
||||||
|
|
||||||
updateFilteredEntries();
|
|
||||||
}, [existingData]);
|
|
||||||
|
|
||||||
function updateFilteredEntries() {
|
|
||||||
if (!updateTimeout.current) {
|
|
||||||
console.log("Updating after timeout");
|
|
||||||
}
|
|
||||||
updateTimeout.current = undefined;
|
|
||||||
|
|
||||||
var filteredEntries = logEntries.current.filter(filterByLogLevel);
|
|
||||||
setFilteredLogEntries(filteredEntries);
|
|
||||||
|
|
||||||
lastUpdate.current = new Date().getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
updateFilteredEntries();
|
|
||||||
}, [logLevel]);
|
|
||||||
|
|
||||||
function convertLogEntry(logEntry : GQL.LogEntryDataFragment) {
|
|
||||||
return new LogEntry(logEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
function levelClass(level : string) {
|
|
||||||
return level.toLowerCase().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ILogElementProps {
|
|
||||||
logEntry : LogEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
function LogElement(props : ILogElementProps) {
|
|
||||||
// pad to maximum length of level enum
|
|
||||||
var level = props.logEntry.level.padEnd(GQL.LogLevel.Progress.length);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<span>{props.logEntry.time}</span>
|
|
||||||
<span className={levelClass(props.logEntry.level)}>{level}</span>
|
|
||||||
<span>{props.logEntry.message}</span>
|
|
||||||
<br/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function maybeRenderError() {
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<span className={"error"}>Error connecting to log server: {error.message}</span><br/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const logLevels = ["Debug", "Info", "Warning", "Error"];
|
|
||||||
|
|
||||||
function filterByLogLevel(logEntry : LogEntry) {
|
function filterByLogLevel(logEntry : LogEntry) {
|
||||||
if (logLevel === "Debug") {
|
if (logLevel === "Debug")
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
var logLevelIndex = logLevels.indexOf(logLevel);
|
var logLevelIndex = logLevels.indexOf(logLevel);
|
||||||
var levelIndex = logLevels.indexOf(logEntry.level);
|
var levelIndex = logLevels.indexOf(logEntry.level);
|
||||||
@@ -179,7 +111,7 @@ export const SettingsLogsPanel: React.FC = () => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Form.Row>
|
</Form.Row>
|
||||||
<div className="logs">
|
<div className="logs">
|
||||||
{maybeRenderError()}
|
{maybeRenderError}
|
||||||
{filteredLogEntries.map((logEntry) =>
|
{filteredLogEntries.map((logEntry) =>
|
||||||
<LogElement logEntry={logEntry} key={logEntry.id}/>
|
<LogElement logEntry={logEntry} key={logEntry.id}/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -118,13 +118,14 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
|||||||
<InputGroup>
|
<InputGroup>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
defaultValue={value}
|
value={value}
|
||||||
onChange={(e : any) => setValue(e.target.value)}
|
onChange={(e : any) => setValue(e.target.value)}
|
||||||
onBlur={() => props.onValueChange(stringToSeconds(value))}
|
onBlur={() => props.onValueChange(stringToSeconds(value))}
|
||||||
placeholder="hh:mm:ss"
|
placeholder="hh:mm:ss"
|
||||||
/>
|
/>
|
||||||
<InputGroup.Append>
|
<InputGroup.Append>
|
||||||
{maybeRenderReset()}
|
{ maybeRenderReset() }
|
||||||
|
{ renderButtons() }
|
||||||
</InputGroup.Append>
|
</InputGroup.Append>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||||||
defaultValue={currentDirectory}
|
defaultValue={currentDirectory}
|
||||||
/>
|
/>
|
||||||
<InputGroup.Append>
|
<InputGroup.Append>
|
||||||
{(!data || !data.directories || loading) ? <Spinner animation="border" variant="light" /> : undefined}
|
{(!data || !data.directories || loading) ? <Spinner animation="border" variant="light" /> : ''}
|
||||||
</InputGroup.Append>
|
</InputGroup.Append>
|
||||||
</InputGroup>
|
</InputGroup>
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||||||
{renderDialog()}
|
{renderDialog()}
|
||||||
<Form.Group>
|
<Form.Group>
|
||||||
{selectedDirectories.map((path) => {
|
{selectedDirectories.map((path) => {
|
||||||
return <div key={path}>{path} <a onClick={() => onRemoveDirectory(path)}>Remove</a></div>;
|
return <div key={path}>{path} <Button variant="link" onClick={() => onRemoveDirectory(path)}>Remove</Button></div>;
|
||||||
})}
|
})}
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Button, Form, Spinner, Table } from 'react-bootstrap';
|
import { Button, Form, Spinner, Table } from 'react-bootstrap';
|
||||||
import _ from "lodash";
|
|
||||||
import { useParams, useHistory } from 'react-router-dom';
|
import { useParams, useHistory } from 'react-router-dom';
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
@@ -48,7 +47,7 @@ export const Performer: React.FC = () => {
|
|||||||
const Scrapers = StashService.useListPerformerScrapers();
|
const Scrapers = StashService.useListPerformerScrapers();
|
||||||
const [queryableScrapers, setQueryableScrapers] = useState<GQL.ListPerformerScrapersListPerformerScrapers[]>([]);
|
const [queryableScrapers, setQueryableScrapers] = useState<GQL.ListPerformerScrapersListPerformerScrapers[]>([]);
|
||||||
|
|
||||||
const { data, error, loading } = StashService.useFindPerformer(id);
|
const { data, error } = StashService.useFindPerformer(id);
|
||||||
const updatePerformer = StashService.usePerformerUpdate(getPerformerInput() as GQL.PerformerUpdateInput);
|
const updatePerformer = StashService.usePerformerUpdate(getPerformerInput() as GQL.PerformerUpdateInput);
|
||||||
const createPerformer = StashService.usePerformerCreate(getPerformerInput() as GQL.PerformerCreateInput);
|
const createPerformer = StashService.usePerformerCreate(getPerformerInput() as GQL.PerformerCreateInput);
|
||||||
const deletePerformer = StashService.usePerformerDestroy(getPerformerInput() as GQL.PerformerDestroyInput);
|
const deletePerformer = StashService.usePerformerDestroy(getPerformerInput() as GQL.PerformerDestroyInput);
|
||||||
@@ -75,19 +74,16 @@ export const Performer: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(loading);
|
setIsLoading(false);
|
||||||
if (!data || !data.findPerformer || error)
|
if(data?.findPerformer)
|
||||||
return;
|
setPerformer(data.findPerformer);
|
||||||
setPerformer(data.findPerformer);
|
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImagePreview(performer.image_path);
|
setImagePreview(performer.image_path);
|
||||||
setImage(undefined);
|
setImage(undefined);
|
||||||
updatePerformerEditState(performer);
|
updatePerformerEditState(performer);
|
||||||
if (!isNew) {
|
setIsEditing(false);
|
||||||
setIsEditing(false);
|
|
||||||
}
|
|
||||||
}, [performer]);
|
}, [performer]);
|
||||||
|
|
||||||
function onImageLoad(this: FileReader) {
|
function onImageLoad(this: FileReader) {
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ export const SceneMarkersPanel: React.FC<ISceneMarkersPanelProps> = (props: ISce
|
|||||||
<div key={marker.id}>
|
<div key={marker.id}>
|
||||||
<hr />
|
<hr />
|
||||||
<div>
|
<div>
|
||||||
<a onClick={() => onClickMarker(marker)}>{marker.title}</a>
|
<Button variant="link" onClick={() => onClickMarker(marker)}>{marker.title}</Button>
|
||||||
{!isEditorOpen ? <a style={{float: "right"}} onClick={() => onOpenEditor(marker)}>Edit</a> : undefined}
|
{!isEditorOpen ? <Button variant="link" style={{float: "right"}} onClick={() => onOpenEditor(marker)}>Edit</Button> : ''}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{TextUtils.secondsToTimestamp(marker.seconds)}
|
{TextUtils.secondsToTimestamp(marker.seconds)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState, useCallback } from "react";
|
||||||
import { Badge, Button, Card, Collapse, Dropdown, DropdownButton, Form, Table, Spinner } from 'react-bootstrap';
|
import { Badge, Button, Card, Collapse, Dropdown, DropdownButton, Form, Table, Spinner } from 'react-bootstrap';
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
@@ -255,10 +255,28 @@ const builtInRecipes = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const initialParserInput = {
|
||||||
|
pattern: "{title}.{ext}",
|
||||||
|
ignoreWords: [],
|
||||||
|
whitespaceCharacters: "._",
|
||||||
|
capitalizeTitle: true,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
findClicked: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialShowFieldsState = new Map<string, boolean>([
|
||||||
|
["Title", true],
|
||||||
|
["Date", true],
|
||||||
|
["Performers", true],
|
||||||
|
["Tags", true],
|
||||||
|
["Studio", true]
|
||||||
|
]);
|
||||||
|
|
||||||
export const SceneFilenameParser: React.FC = () => {
|
export const SceneFilenameParser: React.FC = () => {
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const [parserResult, setParserResult] = useState<SceneParserResult[]>([]);
|
const [parserResult, setParserResult] = useState<SceneParserResult[]>([]);
|
||||||
const [parserInput, setParserInput] = useState<IParserInput>(initialParserInput());
|
const [parserInput, setParserInput] = useState<IParserInput>(initialParserInput);
|
||||||
|
|
||||||
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
||||||
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
||||||
@@ -266,7 +284,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
||||||
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
||||||
|
|
||||||
const [showFields, setShowFields] = useState<Map<string, boolean>>(initialShowFieldsState());
|
const [showFields, setShowFields] = useState<Map<string, boolean>>(initialShowFieldsState);
|
||||||
|
|
||||||
const [totalItems, setTotalItems] = useState<number>(0);
|
const [totalItems, setTotalItems] = useState<number>(0);
|
||||||
|
|
||||||
@@ -275,71 +293,75 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
|
|
||||||
const updateScenes = StashService.useScenesUpdate(getScenesUpdateData());
|
const updateScenes = StashService.useScenesUpdate(getScenesUpdateData());
|
||||||
|
|
||||||
function initialParserInput() {
|
const determineFieldsToHide = useCallback(() => {
|
||||||
return {
|
var pattern = parserInput.pattern;
|
||||||
pattern: "{title}.{ext}",
|
var titleSet = pattern.includes("{title}");
|
||||||
ignoreWords: [],
|
var dateSet = pattern.includes("{date}") ||
|
||||||
whitespaceCharacters: "._",
|
pattern.includes("{dd}") || // don't worry about other partial date fields since this should be implied
|
||||||
capitalizeTitle: true,
|
ParserField.fullDateFields.some((f) => {
|
||||||
page: 1,
|
return pattern.includes("{" + f.field + "}");
|
||||||
pageSize: 20,
|
});
|
||||||
findClicked: false
|
var performerSet = pattern.includes("{performer}");
|
||||||
};
|
var tagSet = pattern.includes("{tag}");
|
||||||
}
|
var studioSet = pattern.includes("{studio}");
|
||||||
|
|
||||||
function initialShowFieldsState() {
|
const newShowFields = new Map<string, boolean>([
|
||||||
return new Map<string, boolean>([
|
["Title", titleSet],
|
||||||
["Title", true],
|
["Date", dateSet],
|
||||||
["Date", true],
|
["Performers", performerSet],
|
||||||
["Performers", true],
|
["Tags", tagSet],
|
||||||
["Tags", true],
|
["Studio", studioSet]
|
||||||
["Studio", true]
|
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
function getParserFilter() {
|
setShowFields(newShowFields);
|
||||||
return {
|
}, [parserInput]);
|
||||||
q: parserInput.pattern,
|
|
||||||
page: parserInput.page,
|
|
||||||
per_page: parserInput.pageSize,
|
|
||||||
sort: "path",
|
|
||||||
direction: GQL.SortDirectionEnum.Asc,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParserInput() {
|
const parseResults = useCallback((results : GQL.ParseSceneFilenamesResults[]) => {
|
||||||
return {
|
if (results) {
|
||||||
ignoreWords: parserInput.ignoreWords,
|
var result = results.map((r) => {
|
||||||
whitespaceCharacters: parserInput.whitespaceCharacters,
|
return new SceneParserResult(r);
|
||||||
capitalizeTitle: parserInput.capitalizeTitle
|
}).filter((r) => !!r) as SceneParserResult[];
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onFind() {
|
setParserResult(result);
|
||||||
setParserResult([]);
|
determineFieldsToHide();
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await StashService.queryParseSceneFilenames(getParserFilter(), getParserInput());
|
|
||||||
|
|
||||||
let result = response.data.parseSceneFilenames;
|
|
||||||
if (result) {
|
|
||||||
parseResults(result.results);
|
|
||||||
setTotalItems(result.count);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
Toast.error(err);
|
|
||||||
}
|
}
|
||||||
|
}, [determineFieldsToHide]);
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(parserInput.findClicked) {
|
if(parserInput.findClicked) {
|
||||||
onFind();
|
setParserResult([]);
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const parserFilter = {
|
||||||
|
q: parserInput.pattern,
|
||||||
|
page: parserInput.page,
|
||||||
|
per_page: parserInput.pageSize,
|
||||||
|
sort: "path",
|
||||||
|
direction: GQL.SortDirectionEnum.Asc,
|
||||||
|
};
|
||||||
|
|
||||||
|
const parserInputData = {
|
||||||
|
ignoreWords: parserInput.ignoreWords,
|
||||||
|
whitespaceCharacters: parserInput.whitespaceCharacters,
|
||||||
|
capitalizeTitle: parserInput.capitalizeTitle
|
||||||
|
};
|
||||||
|
|
||||||
|
StashService.queryParseSceneFilenames(parserFilter, parserInputData)
|
||||||
|
.then((response) => {
|
||||||
|
let result = response.data.parseSceneFilenames;
|
||||||
|
if (result) {
|
||||||
|
parseResults(result.results);
|
||||||
|
setTotalItems(result.count);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => (
|
||||||
|
Toast.error(err)
|
||||||
|
))
|
||||||
|
.finally(() => (
|
||||||
|
setIsLoading(false)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}, [parserInput]);
|
}, [parserInput, parseResults, Toast]);
|
||||||
|
|
||||||
function onPageSizeChanged(newSize : number) {
|
function onPageSizeChanged(newSize : number) {
|
||||||
var newInput = _.clone(parserInput);
|
var newInput = _.clone(parserInput);
|
||||||
@@ -380,38 +402,6 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseResults(results : GQL.ParseSceneFilenamesResults[]) {
|
|
||||||
if (results) {
|
|
||||||
var result = results.map((r) => {
|
|
||||||
return new SceneParserResult(r);
|
|
||||||
}).filter((r) => !!r) as SceneParserResult[];
|
|
||||||
|
|
||||||
setParserResult(result);
|
|
||||||
determineFieldsToHide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function determineFieldsToHide() {
|
|
||||||
var pattern = parserInput.pattern;
|
|
||||||
var titleSet = pattern.includes("{title}");
|
|
||||||
var dateSet = pattern.includes("{date}") ||
|
|
||||||
pattern.includes("{dd}") || // don't worry about other partial date fields since this should be implied
|
|
||||||
ParserField.fullDateFields.some((f) => {
|
|
||||||
return pattern.includes("{" + f.field + "}");
|
|
||||||
});
|
|
||||||
var performerSet = pattern.includes("{performer}");
|
|
||||||
var tagSet = pattern.includes("{tag}");
|
|
||||||
var studioSet = pattern.includes("{studio}");
|
|
||||||
|
|
||||||
var showFieldsCopy = _.clone(showFields);
|
|
||||||
showFieldsCopy.set("Title", titleSet);
|
|
||||||
showFieldsCopy.set("Date", dateSet);
|
|
||||||
showFieldsCopy.set("Performers", performerSet);
|
|
||||||
showFieldsCopy.set("Tags", tagSet);
|
|
||||||
showFieldsCopy.set("Studio", studioSet);
|
|
||||||
setShowFields(showFieldsCopy);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
var newAllTitleSet = !parserResult.some((r) => {
|
var newAllTitleSet = !parserResult.some((r) => {
|
||||||
return !r.title.set;
|
return !r.title.set;
|
||||||
@@ -429,21 +419,11 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
return !r.studioId.set;
|
return !r.studioId.set;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newAllTitleSet !== allTitleSet) {
|
setAllTitleSet(newAllTitleSet);
|
||||||
setAllTitleSet(newAllTitleSet);
|
setAllDateSet(newAllDateSet);
|
||||||
}
|
setAllTagSet(newAllPerformerSet);
|
||||||
if (newAllDateSet !== allDateSet) {
|
setAllTagSet(newAllTagSet);
|
||||||
setAllDateSet(newAllDateSet);
|
setAllStudioSet(newAllStudioSet);
|
||||||
}
|
|
||||||
if (newAllPerformerSet !== allPerformerSet) {
|
|
||||||
setAllTagSet(newAllPerformerSet);
|
|
||||||
}
|
|
||||||
if (newAllTagSet !== allTagSet) {
|
|
||||||
setAllTagSet(newAllTagSet);
|
|
||||||
}
|
|
||||||
if (newAllStudioSet !== allStudioSet) {
|
|
||||||
setAllStudioSet(newAllStudioSet);
|
|
||||||
}
|
|
||||||
}, [parserResult]);
|
}, [parserResult]);
|
||||||
|
|
||||||
function onSelectAllTitleSet(selected : boolean) {
|
function onSelectAllTitleSet(selected : boolean) {
|
||||||
@@ -746,7 +726,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
const elements = parserResult.originalValue
|
const elements = parserResult.originalValue
|
||||||
? Array.isArray(parserResult.originalValue)
|
? Array.isArray(parserResult.originalValue)
|
||||||
? parserResult.originalValue.map((el:HasName) => el.name)
|
? parserResult.originalValue.map((el:HasName) => el.name)
|
||||||
: parserResult.originalValue.name
|
: [parserResult.originalValue.name]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { CSSProperties, useEffect, useRef, useState } from "react";
|
import React, { CSSProperties, useEffect, useRef, useState, useCallback } from "react";
|
||||||
|
import { Button } from 'react-bootstrap';
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { TextUtils } from "src/utils";
|
import { TextUtils } from "src/utils";
|
||||||
@@ -20,6 +21,47 @@ interface ISceneSpriteItem {
|
|||||||
h: number;
|
h: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function fetchSpriteInfo(vttPath: string) {
|
||||||
|
const response = await axios.get<string>(vttPath, {responseType: "text"});
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log(response.statusText);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is gnarly
|
||||||
|
const lines = response.data.split("\n");
|
||||||
|
if (lines.shift() !== "WEBVTT") { return; }
|
||||||
|
if (lines.shift() !== "") { return; }
|
||||||
|
let item: ISceneSpriteItem = {start: 0, end: 0, x: 0, y: 0, w: 0, h: 0};
|
||||||
|
const newSpriteItems: ISceneSpriteItem[] = [];
|
||||||
|
while (lines.length) {
|
||||||
|
const line = lines.shift();
|
||||||
|
if (line === undefined) { continue; }
|
||||||
|
|
||||||
|
if (line.includes("#") && line.includes("=") && line.includes(",")) {
|
||||||
|
const size = line.split("#")[1].split("=")[1].split(",");
|
||||||
|
item.x = Number(size[0]);
|
||||||
|
item.y = Number(size[1]);
|
||||||
|
item.w = Number(size[2]);
|
||||||
|
item.h = Number(size[3]);
|
||||||
|
|
||||||
|
newSpriteItems.push(item);
|
||||||
|
item = {start: 0, end: 0, x: 0, y: 0, w: 0, h: 0};
|
||||||
|
} else if (line.includes(" --> ")) {
|
||||||
|
const times = line.split(" --> ");
|
||||||
|
|
||||||
|
const start = times[0].split(":");
|
||||||
|
item.start = (+start[0]) * 60 * 60 + (+start[1]) * 60 + (+start[2]);
|
||||||
|
|
||||||
|
const end = times[1].split(":");
|
||||||
|
item.end = (+end[0]) * 60 * 60 + (+end[1]) * 60 + (+end[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newSpriteItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props: IScenePlayerScrubberProps) => {
|
export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props: IScenePlayerScrubberProps) => {
|
||||||
const contentEl = useRef<HTMLDivElement>(null);
|
const contentEl = useRef<HTMLDivElement>(null);
|
||||||
const positionIndicatorEl = useRef<HTMLDivElement>(null);
|
const positionIndicatorEl = useRef<HTMLDivElement>(null);
|
||||||
@@ -30,8 +72,8 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
const velocity = useRef(0);
|
const velocity = useRef(0);
|
||||||
|
|
||||||
const _position = useRef(0);
|
const _position = useRef(0);
|
||||||
function getPostion() { return _position.current; }
|
const getPosition = useCallback(() => _position.current, []);
|
||||||
function setPosition(newPostion: number, shouldEmit: boolean = true) {
|
const setPosition = useCallback((newPostion: number, shouldEmit: boolean = true) => {
|
||||||
if (!scrubberSliderEl.current || !positionIndicatorEl.current) { return; }
|
if (!scrubberSliderEl.current || !positionIndicatorEl.current) { return; }
|
||||||
if (shouldEmit) { props.onScrolled(); }
|
if (shouldEmit) { props.onScrolled(); }
|
||||||
|
|
||||||
@@ -52,10 +94,9 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
(newPostion - midpointOffset) / (bounds - (midpointOffset * 2)) * scrubberSliderEl.current.clientWidth
|
(newPostion - midpointOffset) / (bounds - (midpointOffset * 2)) * scrubberSliderEl.current.clientWidth
|
||||||
);
|
);
|
||||||
positionIndicatorEl.current.style.transform = `translateX(${indicatorPosition}px)`;
|
positionIndicatorEl.current.style.transform = `translateX(${indicatorPosition}px)`;
|
||||||
}
|
}, [props]);
|
||||||
|
|
||||||
const [spriteItems, setSpriteItems] = useState<ISceneSpriteItem[]>([]);
|
const [spriteItems, setSpriteItems] = useState<ISceneSpriteItem[]>([]);
|
||||||
const [delayedRender, setDelayedRender] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!scrubberSliderEl.current) { return; }
|
if (!scrubberSliderEl.current) { return; }
|
||||||
@@ -63,7 +104,12 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
}, [scrubberSliderEl]);
|
}, [scrubberSliderEl]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchSpriteInfo();
|
if (!props.scene.paths.vtt)
|
||||||
|
return;
|
||||||
|
fetchSpriteInfo(props.scene.paths.vtt).then((sprites) => {
|
||||||
|
if(sprites)
|
||||||
|
setSpriteItems(sprites);
|
||||||
|
});
|
||||||
}, [props.scene]);
|
}, [props.scene]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -74,7 +120,7 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
(scrubberSliderEl.current.scrollWidth * percentage) - (scrubberSliderEl.current.clientWidth / 2)
|
(scrubberSliderEl.current.scrollWidth * percentage) - (scrubberSliderEl.current.clientWidth / 2)
|
||||||
) * -1;
|
) * -1;
|
||||||
setPosition(position, false);
|
setPosition(position, false);
|
||||||
}, [props.position]);
|
}, [props.position, props.scene.file.duration, setPosition]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener("mouseup", onMouseUp, false);
|
window.addEventListener("mouseup", onMouseUp, false);
|
||||||
@@ -85,19 +131,21 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!contentEl.current) { return; }
|
if (!contentEl.current) { return; }
|
||||||
contentEl.current.addEventListener("mousedown", onMouseDown, false);
|
const el = contentEl.current;
|
||||||
|
el.addEventListener("mousedown", onMouseDown, false);
|
||||||
return () => {
|
return () => {
|
||||||
if (!contentEl.current) { return; }
|
if (!el) { return; }
|
||||||
contentEl.current.removeEventListener("mousedown", onMouseDown);
|
el.removeEventListener("mousedown", onMouseDown);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!contentEl.current) { return; }
|
if (!contentEl.current) { return; }
|
||||||
contentEl.current.addEventListener("mousemove", onMouseMove, false);
|
const el = contentEl.current;
|
||||||
|
el.addEventListener("mousemove", onMouseMove, false);
|
||||||
return () => {
|
return () => {
|
||||||
if (!contentEl.current) { return; }
|
if (!el) { return; }
|
||||||
contentEl.current.removeEventListener("mousemove", onMouseMove);
|
el.removeEventListener("mousemove", onMouseMove);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -125,7 +173,7 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
|
|
||||||
if (!!seekSeconds) { props.onSeek(seekSeconds); }
|
if (!!seekSeconds) { props.onSeek(seekSeconds); }
|
||||||
} else if (Math.abs(velocity.current) > 25) {
|
} else if (Math.abs(velocity.current) > 25) {
|
||||||
const newPosition = getPostion() + (velocity.current * 10);
|
const newPosition = getPosition() + (velocity.current * 10);
|
||||||
setPosition(newPosition);
|
setPosition(newPosition);
|
||||||
velocity.current = 0;
|
velocity.current = 0;
|
||||||
}
|
}
|
||||||
@@ -148,7 +196,7 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
const movement = event.movementX;
|
const movement = event.movementX;
|
||||||
velocity.current = movement;
|
velocity.current = movement;
|
||||||
|
|
||||||
const newPostion = getPostion() + delta;
|
const newPostion = getPosition() + delta;
|
||||||
setPosition(newPostion);
|
setPosition(newPostion);
|
||||||
lastMouseEvent.current = event;
|
lastMouseEvent.current = event;
|
||||||
}
|
}
|
||||||
@@ -160,61 +208,16 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
if (!scrubberSliderEl.current) { return; }
|
if (!scrubberSliderEl.current) { return; }
|
||||||
const newPosition = getPostion() + scrubberSliderEl.current.clientWidth;
|
const newPosition = getPosition() + scrubberSliderEl.current.clientWidth;
|
||||||
setPosition(newPosition);
|
setPosition(newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
function goForward() {
|
function goForward() {
|
||||||
if (!scrubberSliderEl.current) { return; }
|
if (!scrubberSliderEl.current) { return; }
|
||||||
const newPosition = getPostion() - scrubberSliderEl.current.clientWidth;
|
const newPosition = getPosition() - scrubberSliderEl.current.clientWidth;
|
||||||
setPosition(newPosition);
|
setPosition(newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSpriteInfo() {
|
|
||||||
if (!props.scene || !props.scene.paths.vtt) { return; }
|
|
||||||
|
|
||||||
const response = await axios.get<string>(props.scene.paths.vtt, {responseType: "text"});
|
|
||||||
if (response.status !== 200) {
|
|
||||||
console.log(response.statusText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This is gnarly
|
|
||||||
const lines = response.data.split("\n");
|
|
||||||
if (lines.shift() !== "WEBVTT") { return; }
|
|
||||||
if (lines.shift() !== "") { return; }
|
|
||||||
let item: ISceneSpriteItem = {start: 0, end: 0, x: 0, y: 0, w: 0, h: 0};
|
|
||||||
const newSpriteItems: ISceneSpriteItem[] = [];
|
|
||||||
while (lines.length) {
|
|
||||||
const line = lines.shift();
|
|
||||||
if (line === undefined) { continue; }
|
|
||||||
|
|
||||||
if (line.includes("#") && line.includes("=") && line.includes(",")) {
|
|
||||||
const size = line.split("#")[1].split("=")[1].split(",");
|
|
||||||
item.x = Number(size[0]);
|
|
||||||
item.y = Number(size[1]);
|
|
||||||
item.w = Number(size[2]);
|
|
||||||
item.h = Number(size[3]);
|
|
||||||
|
|
||||||
newSpriteItems.push(item);
|
|
||||||
item = {start: 0, end: 0, x: 0, y: 0, w: 0, h: 0};
|
|
||||||
} else if (line.includes(" --> ")) {
|
|
||||||
const times = line.split(" --> ");
|
|
||||||
|
|
||||||
const start = times[0].split(":");
|
|
||||||
item.start = (+start[0]) * 60 * 60 + (+start[1]) * 60 + (+start[2]);
|
|
||||||
|
|
||||||
const end = times[1].split(":");
|
|
||||||
item.end = (+end[0]) * 60 * 60 + (+end[1]) * 60 + (+end[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSpriteItems(newSpriteItems);
|
|
||||||
// TODO: Very hacky. Need to wait for the scroll width to update from the image loading.
|
|
||||||
setTimeout(() => {
|
|
||||||
setDelayedRender(true);
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderTags() {
|
function renderTags() {
|
||||||
function getTagStyle(i: number): CSSProperties {
|
function getTagStyle(i: number): CSSProperties {
|
||||||
if (!scrubberSliderEl.current ||
|
if (!scrubberSliderEl.current ||
|
||||||
@@ -296,7 +299,7 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="scrubber-wrapper">
|
<div className="scrubber-wrapper">
|
||||||
<a className="scrubber-button" id="scrubber-back" onClick={() => goBack()}><</a>
|
<Button variant="link" className="scrubber-button" id="scrubber-back" onClick={() => goBack()}><</Button>
|
||||||
<div ref={contentEl} className="scrubber-content">
|
<div ref={contentEl} className="scrubber-content">
|
||||||
<div className="scrubber-tags-background" />
|
<div className="scrubber-tags-background" />
|
||||||
<div ref={positionIndicatorEl} id="scrubber-position-indicator" />
|
<div ref={positionIndicatorEl} id="scrubber-position-indicator" />
|
||||||
@@ -310,7 +313,7 @@ export const ScenePlayerScrubber: React.FC<IScenePlayerScrubberProps> = (props:
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a className="scrubber-button" id="scrubber-forward" onClick={() => goForward()}>></a>
|
<Button className="scrubber-button" id="scrubber-forward" onClick={() => goForward()}>></Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useContext, createContext } from 'react';
|
import React, { useEffect, useState, useContext, createContext } from 'react';
|
||||||
import { Toast } from 'react-bootstrap';
|
import { Toast } from 'react-bootstrap';
|
||||||
|
|
||||||
interface IToast {
|
interface IToast {
|
||||||
@@ -52,19 +52,28 @@ export const ToastProvider: React.FC = ({children}) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useToasts = () => {
|
function createHookObject(toastFunc: (toast:IToast) => void) {
|
||||||
const setToast = useContext(ToastContext);
|
|
||||||
return {
|
return {
|
||||||
success: setToast,
|
success: toastFunc,
|
||||||
error: (error: Error) => {
|
error: (error: Error) => {
|
||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
setToast({
|
toastFunc({
|
||||||
variant: 'danger',
|
variant: 'danger',
|
||||||
header: 'Error',
|
header: 'Error',
|
||||||
content: error.message ?? error.toString()
|
content: error.message ?? error.toString()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const useToasts = () => {
|
||||||
|
const setToast = useContext(ToastContext);
|
||||||
|
const [hookObject, setHookObject] = useState(createHookObject(setToast));
|
||||||
|
useEffect(() => (
|
||||||
|
setHookObject(createHookObject(setToast))
|
||||||
|
), [setToast]);
|
||||||
|
|
||||||
|
return hookObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useToasts;
|
export default useToasts;
|
||||||
|
|||||||
@@ -4463,6 +4463,13 @@ escodegen@^1.11.0, escodegen@^1.9.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
|
eslint-config-prettier@^6.9.0:
|
||||||
|
version "6.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.9.0.tgz#430d24822e82f7deb1e22a435bfa3999fae4ad64"
|
||||||
|
integrity sha512-k4E14HBtcLv0uqThaI6I/n1LEqROp8XaPu6SO9Z32u5NlGRC07Enu1Bh2KEFw4FNHbekH8yzbIU9kUGxbiGmCA==
|
||||||
|
dependencies:
|
||||||
|
get-stdin "^6.0.0"
|
||||||
|
|
||||||
eslint-config-react-app@^5.1.0:
|
eslint-config-react-app@^5.1.0:
|
||||||
version "5.1.0"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.1.0.tgz#a37b3f2d4f56f856f93277281ef52bd791273e63"
|
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.1.0.tgz#a37b3f2d4f56f856f93277281ef52bd791273e63"
|
||||||
@@ -4536,6 +4543,13 @@ eslint-plugin-jsx-a11y@6.2.3:
|
|||||||
has "^1.0.3"
|
has "^1.0.3"
|
||||||
jsx-ast-utils "^2.2.1"
|
jsx-ast-utils "^2.2.1"
|
||||||
|
|
||||||
|
eslint-plugin-prettier@^3.1.2:
|
||||||
|
version "3.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz#432e5a667666ab84ce72f945c72f77d996a5c9ba"
|
||||||
|
integrity sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==
|
||||||
|
dependencies:
|
||||||
|
prettier-linter-helpers "^1.0.0"
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^1.6.1:
|
eslint-plugin-react-hooks@^1.6.1:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
|
||||||
@@ -4859,6 +4873,11 @@ fast-deep-equal@^2.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||||
|
|
||||||
|
fast-diff@^1.1.2:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||||
|
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||||
|
|
||||||
fast-glob@^2.0.2:
|
fast-glob@^2.0.2:
|
||||||
version "2.2.7"
|
version "2.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
|
||||||
@@ -5311,6 +5330,11 @@ get-stdin@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||||
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
|
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
|
||||||
|
|
||||||
|
get-stdin@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
|
||||||
|
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
|
||||||
|
|
||||||
get-stream@^4.0.0:
|
get-stream@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||||
@@ -9640,6 +9664,13 @@ prepend-http@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||||
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
|
||||||
|
|
||||||
|
prettier-linter-helpers@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
|
||||||
|
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
|
||||||
|
dependencies:
|
||||||
|
fast-diff "^1.1.2"
|
||||||
|
|
||||||
prettier@1.16.4:
|
prettier@1.16.4:
|
||||||
version "1.16.4"
|
version "1.16.4"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717"
|
||||||
|
|||||||
Reference in New Issue
Block a user