Skip to content

Commit

Permalink
Dev Console
Browse files Browse the repository at this point in the history
  • Loading branch information
jcsalterego committed May 5, 2023
1 parent aed8563 commit 106045b
Show file tree
Hide file tree
Showing 11 changed files with 404 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ App icon based on the [work](https://unsplash.com/photos/KVVpx8M10OY) of Carmine
### 0.0.9-pre

* Fix Tab navigation in Dark Mode
* `Advanced > Developer Console`

### 0.0.8

Expand Down
12 changes: 12 additions & 0 deletions Sky.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
objects = {

/* Begin PBXBuildFile section */
041663E32A05376C001A667F /* DevConsoleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041663E22A05376C001A667F /* DevConsoleViewController.swift */; };
043A0F1829A5330E00B06D18 /* Scripts in Resources */ = {isa = PBXBuildFile; fileRef = 043A0F1729A5330E00B06D18 /* Scripts */; };
043A0F1B29A5331800B06D18 /* JsLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043A0F1929A5331800B06D18 /* JsLoader.swift */; };
043A0F1C29A5331800B06D18 /* ScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 043A0F1A29A5331800B06D18 /* ScriptMessageHandler.swift */; };
04DB601B2A0558E7009818AD /* DevConsole in Resources */ = {isa = PBXBuildFile; fileRef = 04DB601A2A0558E7009818AD /* DevConsole */; };
04DB601D2A058B04009818AD /* DevConsoleScriptMessageHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04DB601C2A058B04009818AD /* DevConsoleScriptMessageHandler.swift */; };
04E847CA21D99CE0009D1B0F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04E847C921D99CE0009D1B0F /* AppDelegate.swift */; };
04E847CC21D99CE0009D1B0F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04E847CB21D99CE0009D1B0F /* ViewController.swift */; };
04E847CE21D99CE1009D1B0F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 04E847CD21D99CE1009D1B0F /* Assets.xcassets */; };
Expand Down Expand Up @@ -38,9 +41,12 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
041663E22A05376C001A667F /* DevConsoleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevConsoleViewController.swift; sourceTree = "<group>"; };
043A0F1729A5330E00B06D18 /* Scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Scripts; sourceTree = "<group>"; };
043A0F1929A5331800B06D18 /* JsLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JsLoader.swift; sourceTree = "<group>"; };
043A0F1A29A5331800B06D18 /* ScriptMessageHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScriptMessageHandler.swift; sourceTree = "<group>"; };
04DB601A2A0558E7009818AD /* DevConsole */ = {isa = PBXFileReference; lastKnownFileType = folder; path = DevConsole; sourceTree = "<group>"; };
04DB601C2A058B04009818AD /* DevConsoleScriptMessageHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevConsoleScriptMessageHandler.swift; sourceTree = "<group>"; };
04E847C621D99CE0009D1B0F /* Sky.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sky.app; sourceTree = BUILT_PRODUCTS_DIR; };
04E847C921D99CE0009D1B0F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
04E847CB21D99CE0009D1B0F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -108,10 +114,13 @@
04E847C821D99CE0009D1B0F /* Sky */ = {
isa = PBXGroup;
children = (
04DB601A2A0558E7009818AD /* DevConsole */,
043A0F1729A5330E00B06D18 /* Scripts */,
04E847C921D99CE0009D1B0F /* AppDelegate.swift */,
043A0F1929A5331800B06D18 /* JsLoader.swift */,
043A0F1A29A5331800B06D18 /* ScriptMessageHandler.swift */,
04DB601C2A058B04009818AD /* DevConsoleScriptMessageHandler.swift */,
041663E22A05376C001A667F /* DevConsoleViewController.swift */,
04E847CB21D99CE0009D1B0F /* ViewController.swift */,
04E8481021DA8A5E009D1B0F /* WebKitDelegate.swift */,
04E847CD21D99CE1009D1B0F /* Assets.xcassets */,
Expand Down Expand Up @@ -256,6 +265,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
04DB601B2A0558E7009818AD /* DevConsole in Resources */,
043A0F1829A5330E00B06D18 /* Scripts in Resources */,
04E847CE21D99CE1009D1B0F /* Assets.xcassets in Resources */,
04E847D121D99CE1009D1B0F /* Main.storyboard in Resources */,
Expand Down Expand Up @@ -286,6 +296,8 @@
043A0F1C29A5331800B06D18 /* ScriptMessageHandler.swift in Sources */,
04E8481121DA8A5E009D1B0F /* WebKitDelegate.swift in Sources */,
043A0F1B29A5331800B06D18 /* JsLoader.swift in Sources */,
04DB601D2A058B04009818AD /* DevConsoleScriptMessageHandler.swift in Sources */,
041663E32A05376C001A667F /* DevConsoleViewController.swift in Sources */,
04E847CC21D99CE0009D1B0F /* ViewController.swift in Sources */,
04E847CA21D99CE0009D1B0F /* AppDelegate.swift in Sources */,
);
Expand Down
18 changes: 16 additions & 2 deletions Sky/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,24 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var notificationReadStatuses = [String:Int]()
var firstRun = true

// TODO cleanup, sigh
var mainWindow: NSWindow? = nil
var devConsoleWindowController : NSWindowController?
var devConsoleViewController : DevConsoleViewController?
var accessJwt : String? = nil

func applicationDidBecomeActive(_ notification: Notification) {
if firstRun, let mainWindow = NSApplication.shared.mainWindow {
mainWindow.backgroundColor = NSColor.white
if firstRun {
firstRun = false

mainWindow = NSApplication.shared.mainWindow!
mainWindow?.backgroundColor = NSColor.white

// instantiate dev console
if let storyboard = mainWindow?.windowController?.storyboard {
devConsoleWindowController = storyboard.instantiateController(
withIdentifier: "DevConsoleWindowController") as? NSWindowController
}
}
}

Expand Down
45 changes: 45 additions & 0 deletions Sky/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,13 @@
<action selector="actionOrderPosts:" target="Ady-hI-5gd" id="Clc-2x-R8m"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="NeL-Ie-Lgk"/>
<menuItem title="Developer Console..." keyEquivalent="i" id="ISh-6t-qzI">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="actionOpenDevConsole:" target="Ady-hI-5gd" id="vsu-G6-mrY"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
Expand Down Expand Up @@ -452,5 +459,43 @@
</objects>
<point key="canvasLocation" x="75" y="1077"/>
</scene>
<!--Window Controller-->
<scene sceneID="bdf-pU-Lel">
<objects>
<windowController storyboardIdentifier="DevConsoleWindowController" id="4MQ-4K-03I" sceneMemberID="viewController">
<window key="window" title="Developer Console" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="ClR-S4-DcX">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="211" y="267" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1512" height="944"/>
<view key="contentView" id="vEz-ck-QbU">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<connections>
<outlet property="delegate" destination="4MQ-4K-03I" id="hwu-ot-89F"/>
</connections>
</window>
<connections>
<segue destination="gxx-su-0nF" kind="relationship" relationship="window.shadowedContentViewController" id="qBR-FS-aYS"/>
</connections>
</windowController>
<customObject id="Ea8-ei-kcA" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-405" y="589"/>
</scene>
<!--Dev Console View Controller-->
<scene sceneID="dgQ-Ti-2Pp">
<objects>
<viewController id="gxx-su-0nF" customClass="DevConsoleViewController" customModule="Sky" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="Fki-tr-Qfd">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
</view>
</viewController>
<customObject id="gIy-lZ-cq5" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="554" y="200"/>
</scene>
</scenes>
</document>
178 changes: 178 additions & 0 deletions Sky/DevConsole/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<html>
<head>
<!-- WHEW! this is ugly -->
<style type="text/css">
body {
font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
body, textarea {
background-color: #1e1e1e;
color: #d4d4d4;
}
body, form {
padding: 0;
margin: 0;
}
.auth-and-payload {
display: none;
}
.alert {
background-color: #da464a;
}
.success {
background-color: #0078c9;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-column {
display: flex;
flex-direction: column;
}
.left-gutter {
min-width: 7em;
text-align: right;
}
.left-gutter.label {
padding-top: 0.5em;
}
.right-gutter {
min-width: 5em;
text-align: center;
}
label {
}
.status-bar {
display: none;
}
.monospace {
font-family: monospace;
}
body, pre, code, input, textarea, select, option, .status-bar {
font-size: 14px;
}
.status-bar {
padding: 0.5em;
}
input[type="text"], input[type="password"], input[type="submit"], input[type="button"], select, option, textarea {
margin: 0.5em;
}
input[type="password"] {
min-width: 30em;
}
input[type="text"], input[type="password"] {
flex-grow: 1;
}
.response, .payload {
border: 2px #333 solid;
flex: 1;
min-height: 6em;
}
.container {
min-height: 100%;
}
</style>
</head>
<body>
<div class="container flex-column">
<form class="flex-row">
<div class="left-gutter">
<select class="verb">
<option class="verb-get">GET</option>
</select>
</div>
<input class="url monospace" autofocus type="text" value="">
<div class="right-gutter">
<input type="submit" value="Fetch">
</div>
</form>
<div class="flex-row">
<div class="left-gutter label">Access JWT</div>
<input type="password" class="access-jwt" value="">
<div class="right-gutter">
<input class="load-access-jwt-button" type="button" value="Load">
</div>
</div>
<div class="auth-and-payload">
<div class="flex-row">
<label for="payload">Payload</label>
<textarea class="monospace payload">{}</textarea>
</div>
</div>
<textarea class="monospace response"></textarea>
<div class="status-bar"></div>
</div>
</form>
<script type="text/javascript">
async function changeVerb(ev) {
let verb = document.querySelector(".verb").value;
let authPayloadElem = document.querySelector(".auth-and-payload");
if (verb === "POST") {
authPayloadElem.style.display = "block";
} else {
authPayloadElem.style.display = "none";
}
}
async function run(ev) {
ev.preventDefault();
const url = document.querySelector(".url").value;
console.log("url", url);
let startTime = (new Date()).valueOf();
let method = "GET";
let verb = document.querySelector(".verb").value;
let headers = {};
if (verb == "POST") {
method = verb;
}
let accessJwt = document.querySelector(".access-jwt").value;
if (accessJwt.length > 0) {
headers["Authorization"] = `Bearer ${accessJwt}`;
}
let fetchOptions = {
method: method,
headers: headers,
};
const response = await fetch(url, fetchOptions);
let duration = (new Date()).valueOf() - startTime;
console.log("response", response);
let statusBarElem = document.querySelector(".status-bar");
let responseElem = document.querySelector(".response");
statusBarElem.style.display = "block";
if (response.status === 200) {
const text = await response.text();
const textLength = text.length;
let json = null;
try {
json = JSON.parse(text);
} catch {
// ignore
}
if (json !== null) {
json = JSON.stringify(json, null, 2);
}
responseElem.innerHTML = json;
statusBarElem.classList.remove("alert");
statusBarElem.classList.add("success");
} else {
responseElem.innerHTML = await response.text();
statusBarElem.classList.remove("success");
statusBarElem.classList.add("alert");
}
statusBarElem.innerText =
`HTTP ${response.status} in ${duration} ms`;
}

async function loadAccessJwt() {
window.webkit.messageHandlers.triggerLoadAccessJwt.postMessage({});
}
document.querySelector("form").addEventListener("submit", run);
document.querySelector(".verb").addEventListener("change", changeVerb);
document.querySelector(".load-access-jwt-button").addEventListener("click", loadAccessJwt);

document.querySelector(".verb-get").selected = true
document.querySelector(".url").value = "https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=bsky.app"
changeVerb();

</script>
</body>
46 changes: 46 additions & 0 deletions Sky/DevConsoleScriptMessageHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// DevConsoleScriptMessageHandler.swift
// Sky
//

import WebKit

class DevConsoleScriptMessageHandler: NSObject, WKScriptMessageHandler {

var logging = Bool()
var viewController: DevConsoleViewController!

func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
if message.name == "consoleLog" {
consoleLog(message)
} else if message.name == "triggerLoadAccessJwt" {
triggerLoadAccessJwt(message)
} else {
NSLog("unknown message: \(message)")
}
}

func consoleLog(_ message: WKScriptMessage) {
if let messageBody = message.body as? NSDictionary {
NSLog("console.log: \(messageBody)")
} else if let messageBody = message.body as? String {
NSLog("console.log: \(messageBody)")
} else if let messageBody = message.body as? [Any] {
NSLog("console.log: \(messageBody)")
} else {
NSLog("console.log [unknown type \(type(of:message.body))]: \(message.body)")
}
}

func triggerLoadAccessJwt(_ message: WKScriptMessage) {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
let viewController = appDelegate.mainWindow?.contentViewController as! ViewController
viewController.loadAccessJwt() { id, error in
appDelegate.devConsoleViewController?.populateAccessJwt()
}
}

}
Loading

0 comments on commit 106045b

Please sign in to comment.