Storybook: added ability to mark pages with their status
Closes: #16606
This commit is contained in:
parent
7854271c2e
commit
0c86fbf7b6
|
@ -8,7 +8,6 @@ import Qt.labs.settings 1.0
|
||||||
import StatusQ.Core.Theme 0.1
|
import StatusQ.Core.Theme 0.1
|
||||||
import Storybook 1.0
|
import Storybook 1.0
|
||||||
|
|
||||||
import utils 1.0
|
|
||||||
|
|
||||||
ApplicationWindow {
|
ApplicationWindow {
|
||||||
id: root
|
id: root
|
||||||
|
@ -181,6 +180,7 @@ ApplicationWindow {
|
||||||
model: pagesModel
|
model: pagesModel
|
||||||
|
|
||||||
onPageSelected: root.currentPage = page
|
onPageSelected: root.currentPage = page
|
||||||
|
onStatusClicked: statusStatsDialog.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,17 +287,8 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog {
|
NoFigmaTokenDialog {
|
||||||
id: noFigmaTokenDialog
|
id: noFigmaTokenDialog
|
||||||
|
|
||||||
anchors.centerIn: Overlay.overlay
|
|
||||||
|
|
||||||
title: "Figma token not set"
|
|
||||||
standardButtons: Dialog.Ok
|
|
||||||
|
|
||||||
Label {
|
|
||||||
text: "Please set Figma personal token in \"Settings\""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FigmaLinksCache {
|
FigmaLinksCache {
|
||||||
|
@ -310,24 +301,16 @@ ApplicationWindow {
|
||||||
id: inspectionWindow
|
id: inspectionWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog {
|
NothingToInspectDialog {
|
||||||
id: nothingToInspectDialog
|
id: nothingToInspectDialog
|
||||||
|
|
||||||
anchors.centerIn: Overlay.overlay
|
pageName: root.currentPage
|
||||||
width: contentItem.implicitWidth + leftPadding + rightPadding
|
|
||||||
|
|
||||||
title: "No items to inspect found"
|
|
||||||
standardButtons: Dialog.Ok
|
|
||||||
modal: true
|
|
||||||
|
|
||||||
contentItem: Label {
|
|
||||||
text: '
|
|
||||||
Tips:\n\
|
|
||||||
• For inline components use naming convention of adding\n\
|
|
||||||
"Custom" at the begining (like Custom'+root.currentPage+')\n\
|
|
||||||
• For popups set closePolicy to "Popup.NoAutoClose"\n\
|
|
||||||
'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StatusStatisticsDialog {
|
||||||
|
id: statusStatsDialog
|
||||||
|
|
||||||
|
pagesModel: pagesModel
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
|
||||||
import QtQuick.Layouts 1.15
|
import QtQuick.Layouts 1.15
|
||||||
import QtQml 2.15
|
import QtQml 2.15
|
||||||
|
|
||||||
|
import StatusQ 0.1
|
||||||
import StatusQ.Core 0.1
|
import StatusQ.Core 0.1
|
||||||
import StatusQ.Core.Utils 0.1
|
import StatusQ.Core.Utils 0.1
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
|
@ -27,3 +28,4 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// category: _
|
// category: _
|
||||||
|
// status: good
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include "directoryfileswatcher.h"
|
#include "directoryfileswatcher.h"
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const auto categoryUncategorized QStringLiteral("Uncategorized");
|
const auto categoryUncategorized QStringLiteral("Uncategorized");
|
||||||
}
|
}
|
||||||
|
@ -35,29 +34,9 @@ PagesModelItem PagesModel::readMetadata(const QString& path)
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
QByteArray content = file.readAll();
|
QByteArray content = file.readAll();
|
||||||
|
|
||||||
static QRegularExpression categoryRegex(
|
item.category = extractCategory(content);
|
||||||
"^//(\\s)*category:(.+)$", QRegularExpression::MultilineOption);
|
item.status = extractStatus(content);
|
||||||
|
item.figmaLinks = extractFigmaLinks(content);
|
||||||
QRegularExpressionMatch categoryMatch = categoryRegex.match(content);
|
|
||||||
QString category = categoryMatch.hasMatch()
|
|
||||||
? categoryMatch.captured(2).trimmed() : categoryUncategorized;
|
|
||||||
|
|
||||||
item.category = category.size() ? category : categoryUncategorized;
|
|
||||||
|
|
||||||
static QRegularExpression figmaRegex(
|
|
||||||
"^(\\/\\/\\s*)((?:https:\\/\\/)?(?:www\\.)?figma\\.com\\/.*)$",
|
|
||||||
QRegularExpression::MultilineOption);
|
|
||||||
|
|
||||||
QRegularExpressionMatchIterator i = figmaRegex.globalMatch(content);
|
|
||||||
QStringList links;
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
QRegularExpressionMatch match = i.next();
|
|
||||||
QString link = match.captured(2);
|
|
||||||
links << link;
|
|
||||||
}
|
|
||||||
|
|
||||||
item.figmaLinks = links;
|
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +54,55 @@ QList<PagesModelItem> PagesModel::readMetadata(const QStringList &paths)
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PagesModel::extractCategory(const QByteArray& content)
|
||||||
|
{
|
||||||
|
static QRegularExpression categoryRegex(
|
||||||
|
"^//(\\s)*category:(.+)$", QRegularExpression::MultilineOption);
|
||||||
|
|
||||||
|
QRegularExpressionMatch categoryMatch = categoryRegex.match(content);
|
||||||
|
QString category = categoryMatch.hasMatch()
|
||||||
|
? categoryMatch.captured(2).trimmed() : categoryUncategorized;
|
||||||
|
|
||||||
|
return category.isEmpty() ? categoryUncategorized : category;
|
||||||
|
}
|
||||||
|
|
||||||
|
PagesModel::Status PagesModel::extractStatus(const QByteArray& content)
|
||||||
|
{
|
||||||
|
static QRegularExpression statusRegex(
|
||||||
|
"^//(\\s)*status:(.+)$", QRegularExpression::MultilineOption);
|
||||||
|
|
||||||
|
QRegularExpressionMatch statusMatch = statusRegex.match(content);
|
||||||
|
QString status = statusMatch.hasMatch()
|
||||||
|
? statusMatch.captured(2).trimmed() : "";
|
||||||
|
|
||||||
|
if (status == QStringLiteral("bad"))
|
||||||
|
return Bad;
|
||||||
|
if (status == QStringLiteral("decent"))
|
||||||
|
return Decent;
|
||||||
|
if (status == QStringLiteral("good"))
|
||||||
|
return Good;
|
||||||
|
|
||||||
|
return Uncategorized;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList PagesModel::extractFigmaLinks(const QByteArray& content)
|
||||||
|
{
|
||||||
|
static QRegularExpression figmaRegex(
|
||||||
|
"^(\\/\\/\\s*)((?:https:\\/\\/)?(?:www\\.)?figma\\.com\\/.*)$",
|
||||||
|
QRegularExpression::MultilineOption);
|
||||||
|
|
||||||
|
QRegularExpressionMatchIterator i = figmaRegex.globalMatch(content);
|
||||||
|
QStringList links;
|
||||||
|
|
||||||
|
while (i.hasNext()) {
|
||||||
|
QRegularExpressionMatch match = i.next();
|
||||||
|
QString link = match.captured(2);
|
||||||
|
links << link;
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
void PagesModel::onPagesChanged(const QStringList& added,
|
void PagesModel::onPagesChanged(const QStringList& added,
|
||||||
const QStringList& removed,
|
const QStringList& removed,
|
||||||
const QStringList& changed)
|
const QStringList& changed)
|
||||||
|
@ -106,10 +134,11 @@ void PagesModel::onPagesChanged(const QStringList& added,
|
||||||
PagesModelItem metadata = readMetadata(path);
|
PagesModelItem metadata = readMetadata(path);
|
||||||
setFigmaLinks(metadata.title, metadata.figmaLinks);
|
setFigmaLinks(metadata.title, metadata.figmaLinks);
|
||||||
|
|
||||||
if (previous.category != metadata.category) {
|
// For simplicity category and status change is handled by removing and
|
||||||
// For simplicity category change is handled by removing and
|
|
||||||
// adding item. In the future it can be changed to regular dataChanged
|
// adding item. In the future it can be changed to regular dataChanged
|
||||||
// event and handled properly in upstream models like SectionSDecoratorModel.
|
// event and handled properly in upstream models like SectionSDecoratorModel.
|
||||||
|
if (previous.category != metadata.category
|
||||||
|
|| previous.status != metadata.status) {
|
||||||
beginRemoveRows({}, index, index);
|
beginRemoveRows({}, index, index);
|
||||||
m_items.removeAt(index);
|
m_items.removeAt(index);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
@ -135,6 +164,7 @@ QHash<int, QByteArray> PagesModel::roleNames() const
|
||||||
static const QHash<int,QByteArray> roles {
|
static const QHash<int,QByteArray> roles {
|
||||||
{ TitleRole, QByteArrayLiteral("title") },
|
{ TitleRole, QByteArrayLiteral("title") },
|
||||||
{ CategoryRole, QByteArrayLiteral("category") },
|
{ CategoryRole, QByteArrayLiteral("category") },
|
||||||
|
{ StatusRole, QByteArrayLiteral("status") },
|
||||||
{ FigmaRole, QByteArrayLiteral("figma") }
|
{ FigmaRole, QByteArrayLiteral("figma") }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,6 +187,9 @@ QVariant PagesModel::data(const QModelIndex &index, int role) const
|
||||||
if (role == CategoryRole)
|
if (role == CategoryRole)
|
||||||
return m_items.at(index.row()).category;
|
return m_items.at(index.row()).category;
|
||||||
|
|
||||||
|
if (role == StatusRole)
|
||||||
|
return m_items.at(index.row()).status;
|
||||||
|
|
||||||
if (role == FigmaRole) {
|
if (role == FigmaRole) {
|
||||||
auto title = m_items.at(index.row()).title;
|
auto title = m_items.at(index.row()).title;
|
||||||
auto it = m_figmaSubmodels.find(title);
|
auto it = m_figmaSubmodels.find(title);
|
||||||
|
|
|
@ -12,6 +12,7 @@ struct PagesModelItem {
|
||||||
QDateTime lastModified;
|
QDateTime lastModified;
|
||||||
QString title;
|
QString title;
|
||||||
QString category;
|
QString category;
|
||||||
|
int status = 0;
|
||||||
QStringList figmaLinks;
|
QStringList figmaLinks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,14 +25,23 @@ public:
|
||||||
enum Roles {
|
enum Roles {
|
||||||
TitleRole = Qt::UserRole + 1,
|
TitleRole = Qt::UserRole + 1,
|
||||||
CategoryRole,
|
CategoryRole,
|
||||||
|
StatusRole,
|
||||||
FigmaRole
|
FigmaRole
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Status : int {
|
||||||
|
Uncategorized = 0,
|
||||||
|
Bad,
|
||||||
|
Decent,
|
||||||
|
Good
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_ENUM(Status)
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onPagesChanged(const QStringList& added, const QStringList& removed,
|
void onPagesChanged(const QStringList& added, const QStringList& removed,
|
||||||
const QStringList& changed);
|
const QStringList& changed);
|
||||||
|
@ -44,6 +54,10 @@ private:
|
||||||
static void readMetadata(PagesModelItem &item);
|
static void readMetadata(PagesModelItem &item);
|
||||||
static void readMetadata(QList<PagesModelItem> &items);
|
static void readMetadata(QList<PagesModelItem> &items);
|
||||||
|
|
||||||
|
static QString extractCategory(const QByteArray& content);
|
||||||
|
static PagesModel::Status extractStatus(const QByteArray& content);
|
||||||
|
static QStringList extractFigmaLinks(const QByteArray& content);
|
||||||
|
|
||||||
void setFigmaLinks(const QString& title, const QStringList& links);
|
void setFigmaLinks(const QString& title, const QStringList& links);
|
||||||
|
|
||||||
QString m_path;
|
QString m_path;
|
||||||
|
|
|
@ -13,6 +13,7 @@ ColumnLayout {
|
||||||
property alias currentPage: pagesList.currentPage
|
property alias currentPage: pagesList.currentPage
|
||||||
|
|
||||||
signal pageSelected(string page)
|
signal pageSelected(string page)
|
||||||
|
signal statusClicked
|
||||||
|
|
||||||
SortFilterProxyModel {
|
SortFilterProxyModel {
|
||||||
id: filteredModel
|
id: filteredModel
|
||||||
|
@ -96,5 +97,6 @@ ColumnLayout {
|
||||||
|
|
||||||
onPageSelected: root.pageSelected(page)
|
onPageSelected: root.pageSelected(page)
|
||||||
onSectionClicked: sectionsModel.flipFolding(index)
|
onSectionClicked: sectionsModel.flipFolding(index)
|
||||||
|
onStatusClicked: root.statusClicked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
|
||||||
|
title: "Figma token not set"
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Please set Figma personal token in \"Settings\""
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string pageName
|
||||||
|
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
width: contentItem.implicitWidth + leftPadding + rightPadding
|
||||||
|
|
||||||
|
title: "No items to inspect found"
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
contentItem: Label {
|
||||||
|
text: '
|
||||||
|
Tips:\n\
|
||||||
|
• For inline components use naming convention of adding\n\
|
||||||
|
"Custom" at the begining (like Custom'+root.pageName+')\n\
|
||||||
|
• For popups set closePolicy to "Popup.NoAutoClose"\n\
|
||||||
|
'
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
import QtQuick 2.14
|
import QtQuick 2.15
|
||||||
import QtQuick.Controls 2.14
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: root
|
id: root
|
||||||
|
@ -10,6 +12,7 @@ ListView {
|
||||||
|
|
||||||
signal pageSelected(string page)
|
signal pageSelected(string page)
|
||||||
signal sectionClicked(int index)
|
signal sectionClicked(int index)
|
||||||
|
signal statusClicked
|
||||||
|
|
||||||
readonly property string foldedPrefix: "▶ "
|
readonly property string foldedPrefix: "▶ "
|
||||||
readonly property string unfoldedPrefix: "▼ "
|
readonly property string unfoldedPrefix: "▼ "
|
||||||
|
@ -27,6 +30,35 @@ ListView {
|
||||||
"text/uri-list": `file:${pagesFolder}/${model.title}Page.qml`
|
"text/uri-list": `file:${pagesFolder}/${model.title}Page.qml`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indicator: Rectangle {
|
||||||
|
visible: !model.isSection
|
||||||
|
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: parent.leftPadding / 2
|
||||||
|
|
||||||
|
width: 6
|
||||||
|
height: 6
|
||||||
|
radius: 3
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (model.status === PagesModel.Good)
|
||||||
|
return "green"
|
||||||
|
if (model.status === PagesModel.Decent)
|
||||||
|
return "orange"
|
||||||
|
if (model.status === PagesModel.Bad)
|
||||||
|
return "red"
|
||||||
|
|
||||||
|
return "gray"
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onClicked: root.statusClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: dragArea
|
id: dragArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import StatusQ 0.1
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property var pagesModel
|
||||||
|
|
||||||
|
readonly property string contributingMdLink:
|
||||||
|
"https://github.com/status-im/status-desktop/blob/master/" +
|
||||||
|
"CONTRIBUTING.md#page-classification"
|
||||||
|
|
||||||
|
anchors.centerIn: Overlay.overlay
|
||||||
|
width: 420
|
||||||
|
|
||||||
|
title: "Page status statistics"
|
||||||
|
standardButtons: Dialog.Ok
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property int total: root.pagesModel.ModelCount.count
|
||||||
|
|
||||||
|
function percent(val) {
|
||||||
|
return (val / total * 100).toFixed(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
Label {
|
||||||
|
Layout.bottomMargin: 20
|
||||||
|
|
||||||
|
text: `Total number of pages: ${d.total}`
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: [
|
||||||
|
{ status: "good", color: "green" },
|
||||||
|
{ status: "decent", color: "orange" },
|
||||||
|
{ status: "bad", color: "red" },
|
||||||
|
{ status: "uncategorized", color: "gray" }
|
||||||
|
]
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
readonly property int size: label.height - 2
|
||||||
|
|
||||||
|
width: size
|
||||||
|
height: size
|
||||||
|
radius: size / 2
|
||||||
|
color: modelData.color
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
readonly property string status: modelData.status
|
||||||
|
readonly property int count: statusAggregator[status]
|
||||||
|
|
||||||
|
text: `${status}: ${count} (${d.percent(count)}%)`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.topMargin: 20
|
||||||
|
|
||||||
|
text: `For details check <a href="${root.contributingMdLink}">CONTRIBUTING.md</a>`
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionAggregator {
|
||||||
|
id: statusAggregator
|
||||||
|
|
||||||
|
readonly property int bad: value.bad
|
||||||
|
readonly property int decent: value.decent
|
||||||
|
readonly property int good: value.good
|
||||||
|
readonly property int uncategorized: value.uncategorized
|
||||||
|
|
||||||
|
model: root.pagesModel
|
||||||
|
roleName: "status"
|
||||||
|
|
||||||
|
initialValue: ({
|
||||||
|
bad: 0,
|
||||||
|
decent: 0,
|
||||||
|
good: 0,
|
||||||
|
uncategorized: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
aggregateFunction: (aggr, value) => {
|
||||||
|
let { bad, decent, good, uncategorized } = aggr
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case PagesModel.Bad: bad++; break
|
||||||
|
case PagesModel.Decent: decent++; break
|
||||||
|
case PagesModel.Good: good++; break
|
||||||
|
default: uncategorized++
|
||||||
|
}
|
||||||
|
|
||||||
|
return { bad, decent, good, uncategorized }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ LimitProxyModel 1.0 LimitProxyModel.qml
|
||||||
Logs 1.0 Logs.qml
|
Logs 1.0 Logs.qml
|
||||||
LogsAndControlsPanel 1.0 LogsAndControlsPanel.qml
|
LogsAndControlsPanel 1.0 LogsAndControlsPanel.qml
|
||||||
LogsView 1.0 LogsView.qml
|
LogsView 1.0 LogsView.qml
|
||||||
|
NoFigmaTokenDialog 1.0 NoFigmaTokenDialog.qml
|
||||||
|
NothingToInspectDialog 1.0 NothingToInspectDialog.qml
|
||||||
PageToolBar 1.0 PageToolBar.qml
|
PageToolBar 1.0 PageToolBar.qml
|
||||||
PagesList 1.0 PagesList.qml
|
PagesList 1.0 PagesList.qml
|
||||||
PopupBackground 1.0 PopupBackground.qml
|
PopupBackground 1.0 PopupBackground.qml
|
||||||
|
@ -28,6 +30,7 @@ RadioButtonFlowSelector 1.0 RadioButtonFlowSelector.qml
|
||||||
SettingsLayout 1.0 SettingsLayout.qml
|
SettingsLayout 1.0 SettingsLayout.qml
|
||||||
SingleItemProxyModel 1.0 SingleItemProxyModel.qml
|
SingleItemProxyModel 1.0 SingleItemProxyModel.qml
|
||||||
SourceCodeBox 1.0 SourceCodeBox.qml
|
SourceCodeBox 1.0 SourceCodeBox.qml
|
||||||
|
StatusStatisticsDialog 1.0 StatusStatisticsDialog.qml
|
||||||
TestRunnerController 1.0 TestRunnerController.qml
|
TestRunnerController 1.0 TestRunnerController.qml
|
||||||
TestRunnerControls 1.0 TestRunnerControls.qml
|
TestRunnerControls 1.0 TestRunnerControls.qml
|
||||||
singleton FigmaUtils 1.0 FigmaUtils.qml
|
singleton FigmaUtils 1.0 FigmaUtils.qml
|
||||||
|
|
Loading…
Reference in New Issue