mirror of
https://github.com/foss42/apidash.git
synced 2025-06-02 07:46:10 +08:00
Merge branch 'main' into resolve-issue-history-clear
This commit is contained in:
BIN
doc/dev_guide/images/choco_chocolateyinstall_ps1.png
Normal file
BIN
doc/dev_guide/images/choco_chocolateyinstall_ps1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
doc/dev_guide/images/choco_create_structure.png
Normal file
BIN
doc/dev_guide/images/choco_create_structure.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
BIN
doc/dev_guide/images/choco_nuspec.png
Normal file
BIN
doc/dev_guide/images/choco_nuspec.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
BIN
doc/dev_guide/images/choco_shell_output.png
Normal file
BIN
doc/dev_guide/images/choco_shell_output.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
@ -1,5 +1,14 @@
|
||||
# Packaging API Dash
|
||||
|
||||
- [Windows](#windows)
|
||||
- [macOS](#macos)
|
||||
- [Linux Debian (.deb) & RPM (.rpm)](#linux-debian-deb--rpm-rpm)
|
||||
- [Arch Linux (PKGBUILD)](#arch-linux-pkgbuild)
|
||||
- [FlatHub (Flatpak)](#flathub-flatpak)
|
||||
- [Homebrew](#homebrew)
|
||||
- [Chocolatey](#chocolatey)
|
||||
- [WinGet](#winget)
|
||||
|
||||
## Windows
|
||||
|
||||
[Packaging and Distributing Flutter Desktop Apps : Creating Windows .exe installer](https://medium.com/@fluttergems/packaging-and-distributing-flutter-desktop-apps-the-missing-guide-for-open-source-indie-0b468d5e9e70)
|
||||
@ -22,11 +31,172 @@ TODO Instructions
|
||||
|
||||
## Homebrew
|
||||
|
||||
TODO Instructions
|
||||
Homebrew Formula Submission
|
||||
|
||||
### 1. Prepare Tap Repository
|
||||
|
||||
```
|
||||
# Create Homebrew tap
|
||||
gh repo create homebrew-tap --public --clone
|
||||
mkdir -p homebrew-tap/Formula
|
||||
cd homebrew-tap
|
||||
```
|
||||
|
||||
### 2. Package apidash
|
||||
|
||||
```
|
||||
# Build macOS bundle
|
||||
flutter build macos
|
||||
|
||||
# Create versioned tarball
|
||||
tar -czvf apidash-v1.0.0.tar.gz \
|
||||
-C build/macos/Build/Products/Release/ \
|
||||
Apidash.app
|
||||
|
||||
# Generate SHA256 checksum
|
||||
shasum -a 256 apidash-v1.0.0.tar.gz
|
||||
```
|
||||
|
||||
### 3. Create Formula File
|
||||
|
||||
`Formula/apidash.rb`:
|
||||
|
||||
```
|
||||
class Apidash < Formula
|
||||
desc "Modern API dashboard for developers"
|
||||
homepage "https://apidash.dev"
|
||||
url "https://github.com/<user>/<repo>/releases/download/v1.0.0/apidash-v1.0.0.tar.gz"
|
||||
sha256 "PASTE_YOUR_SHA256_HERE"
|
||||
|
||||
def install
|
||||
prefix.install "Apidash.app"
|
||||
bin.write_exec_script prefix/"Apidash.app/Contents/MacOS/Apidash"
|
||||
end
|
||||
|
||||
test do
|
||||
system "#{bin}/Apidash", "--version"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### 4. Local Validation
|
||||
|
||||
```
|
||||
# Check formula syntax
|
||||
brew audit --strict Formula/apidash.rb
|
||||
|
||||
# Test installation
|
||||
brew install --build-from-source Formula/apidash.rb
|
||||
|
||||
# Verify execution
|
||||
brew test apidash
|
||||
```
|
||||
|
||||
### 5. Custom Tap Submission
|
||||
|
||||
```
|
||||
# Commit formula to your tap repo
|
||||
git add Formula/Apidash.rb
|
||||
git commit -m "added apidash formula"
|
||||
git push
|
||||
|
||||
# Create release for tarball
|
||||
gh release create v1.0.0 apidash-v1.0.0.tar.gz
|
||||
```
|
||||
|
||||
### 6. Installation
|
||||
|
||||
```
|
||||
brew tap homebrew-tap/Formula
|
||||
brew install apidash
|
||||
```
|
||||
|
||||
## Chocolatey
|
||||
|
||||
TODO Instructions
|
||||
### Step 1: Setup Skeleton
|
||||
|
||||
First step towards making a choco package is initializing a base.
|
||||
|
||||
The command `choco new -h` can teach you more about the `new` command, its usage, options, switches, and exit codes.
|
||||
|
||||
Run the following command to setup the base
|
||||
|
||||
```powershell
|
||||
choco new --name="apidash" --version="0.3.0" maintainername="foss42" maintainerrepo="https://github.com/foss42/apidash" --built-in-template
|
||||
```
|
||||
|
||||

|
||||
|
||||
This creates the following folder structure
|
||||
|
||||
```
|
||||
apidash
|
||||
├── ReadMe.md
|
||||
├── _TODO.txt
|
||||
├── apidash.nuspec
|
||||
└── tools
|
||||
├── chocolateybeforemodify.ps1
|
||||
├── chocolateyinstall.ps1
|
||||
├── chocolateyuninstall.ps1
|
||||
├── LICENSE.txt
|
||||
└── VERIFICATION.txt
|
||||
```
|
||||
|
||||
The files `ReadMe.md` and `_TODO.md` can be deleted before pushing.
|
||||
|
||||
The files of our main interest are `chocolateyinstall.ps1` and `apidash.nuspec`.
|
||||
|
||||
### Step 2: Editing `chocolateyinstall.ps1`
|
||||
|
||||
Take a look at `chocolateyinstall.ps1` file. There are many comments stating the use case of each line itself.
|
||||

|
||||
|
||||
Comments can bre remoed using the following command.
|
||||
```powershell
|
||||
$f='apidash\tools\chocolateyinstall.ps1'
|
||||
gc $f | ? {$_ -notmatch "^\s*#"} | % {$_ -replace '(^.*?)\s*? [^``]#.*','$1'} | Out-File $f+".~" -en utf8; mv -fo $f+".~" $f
|
||||
```
|
||||
|
||||
Now our `chocolateyinstall.ps1` file is ready.
|
||||
|
||||
### Step 3: Editing `apidash.nuspec`
|
||||
|
||||

|
||||
|
||||
### Step 4: Build the package
|
||||
|
||||
All our files are ready, we just need to pack out files in a choco package with the extension `.nupkg`.
|
||||
|
||||
Run the following command from the root of your directory:
|
||||
```powershell
|
||||
choco pack
|
||||
```
|
||||
This command generates the `apidash.0.3.0.nupkg` file.
|
||||
|
||||
### Step 5: Test the Package Locally
|
||||
|
||||
Install the package locally using Chocolatey:
|
||||
```powershell
|
||||
choco install apidash -s .
|
||||
```
|
||||
Ensure the application installs correctly.
|
||||
|
||||

|
||||
|
||||
### Step 6: Pre-Publishing - Update `LICENSE.txt` & `VERIFICATION.txt`
|
||||
|
||||
Update `LICENSE.txt` with the actual **LICENSE **and `VERIFICATION.txt` accordingly.
|
||||
|
||||
### Step 7: Publish the Package (Optional)
|
||||
|
||||
To share the package, you can push it to a Chocolatey repository. For the official Chocolatey Community Repository, follow these steps:
|
||||
|
||||
1. Create an account on the Chocolatey Community.
|
||||
2. Get an API key by navigating to your profile.
|
||||
3. Use the following command to push your package:
|
||||
```powershell
|
||||
choco push apidash.0.3.0.nupkg --source="https://push.chocolatey.org/" --api-key="YOUR_API_KEY"
|
||||
```
|
||||
|
||||
## WinGet
|
||||
|
||||
|
@ -25,14 +25,11 @@ final requestSequenceProvider = StateProvider<List<String>>((ref) {
|
||||
return ids ?? [];
|
||||
});
|
||||
|
||||
final httpClientManager = HttpClientManager();
|
||||
|
||||
final StateNotifierProvider<CollectionStateNotifier, Map<String, RequestModel>?>
|
||||
collectionStateNotifierProvider =
|
||||
StateNotifierProvider((ref) => CollectionStateNotifier(
|
||||
ref,
|
||||
hiveHandler,
|
||||
httpClientManager,
|
||||
));
|
||||
|
||||
class CollectionStateNotifier
|
||||
@ -40,7 +37,6 @@ class CollectionStateNotifier
|
||||
CollectionStateNotifier(
|
||||
this.ref,
|
||||
this.hiveHandler,
|
||||
this.httpClientManager,
|
||||
) : super(null) {
|
||||
var status = loadData();
|
||||
Future.microtask(() {
|
||||
@ -57,7 +53,6 @@ class CollectionStateNotifier
|
||||
final Ref ref;
|
||||
final HiveHandler hiveHandler;
|
||||
final baseHttpResponseModel = const HttpResponseModel();
|
||||
final HttpClientManager httpClientManager;
|
||||
|
||||
bool hasId(String id) => state?.keys.contains(id) ?? false;
|
||||
|
||||
@ -117,6 +112,7 @@ class CollectionStateNotifier
|
||||
final rId = id ?? ref.read(selectedIdStateProvider);
|
||||
var itemIds = ref.read(requestSequenceProvider);
|
||||
int idx = itemIds.indexOf(rId!);
|
||||
cancelHttpRequest(rId);
|
||||
itemIds.remove(rId);
|
||||
ref.read(requestSequenceProvider.notifier).state = [...itemIds];
|
||||
|
||||
@ -293,7 +289,7 @@ class CollectionStateNotifier
|
||||
state = map;
|
||||
|
||||
bool noSSL = ref.read(settingsProvider).isSSLDisabled;
|
||||
(HttpResponse?, Duration?, String?)? responseRec = await request(
|
||||
var responseRec = await sendHttpRequest(
|
||||
requestId,
|
||||
apiType,
|
||||
substitutedHttpRequestModel,
|
||||
@ -349,7 +345,7 @@ class CollectionStateNotifier
|
||||
|
||||
void cancelRequest() {
|
||||
final id = ref.read(selectedIdStateProvider);
|
||||
httpClientManager.cancelRequest(id);
|
||||
cancelHttpRequest(id);
|
||||
unsave();
|
||||
}
|
||||
|
||||
|
@ -89,4 +89,11 @@ class HistoryMetaStateNotifier
|
||||
await hiveHandler.setHistoryRequest(id, model.toJson());
|
||||
await loadHistoryRequest(id);
|
||||
}
|
||||
|
||||
Future<void> clearAllHistory() async {
|
||||
await hiveHandler.clearAllHistory();
|
||||
ref.read(selectedHistoryIdStateProvider.notifier).state = null;
|
||||
ref.read(selectedHistoryRequestModelProvider.notifier).state = null;
|
||||
loadHistoryMetas();
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import 'package:apidash/services/services.dart';
|
||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:apidash_design_system/apidash_design_system.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import '../../../consts.dart';
|
||||
|
||||
class HistorySidebarHeader extends ConsumerWidget {
|
||||
const HistorySidebarHeader({super.key});
|
||||
@ -23,12 +22,12 @@ class HistorySidebarHeader extends ConsumerWidget {
|
||||
),
|
||||
const Spacer(),
|
||||
ADIconButton(
|
||||
icon: Icons.delete_forever,
|
||||
iconSize: kButtonIconSizeLarge,
|
||||
tooltip: "Clear History",
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? kColorDarkDanger
|
||||
: kColorLightDanger,
|
||||
icon: Icons.delete_forever,
|
||||
iconSize: kButtonIconSizeLarge,
|
||||
tooltip: "Clear History",
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? kColorDarkDanger
|
||||
: kColorLightDanger,
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
@ -43,7 +42,9 @@ class HistorySidebarHeader extends ConsumerWidget {
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
await hiveHandler.clearAllHistory(ref); // ✅ Pass `ref` here
|
||||
await ref
|
||||
.read(historyMetaStateNotifier.notifier)
|
||||
.clearAllHistory();
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
|
@ -10,15 +10,16 @@ import 'http_client_manager.dart';
|
||||
|
||||
typedef HttpResponse = http.Response;
|
||||
|
||||
Future<(HttpResponse?, Duration?, String?)> request(
|
||||
final httpClientManager = HttpClientManager();
|
||||
|
||||
Future<(HttpResponse?, Duration?, String?)> sendHttpRequest(
|
||||
String requestId,
|
||||
APIType apiType,
|
||||
HttpRequestModel requestModel, {
|
||||
SupportedUriSchemes defaultUriScheme = kDefaultUriScheme,
|
||||
bool noSSL = false,
|
||||
}) async {
|
||||
final clientManager = HttpClientManager();
|
||||
final client = clientManager.createClient(requestId, noSSL: noSSL);
|
||||
final client = httpClientManager.createClient(requestId, noSSL: noSSL);
|
||||
|
||||
(Uri?, String?) uriRec = getValidRequestUri(
|
||||
requestModel.url,
|
||||
@ -123,14 +124,19 @@ Future<(HttpResponse?, Duration?, String?)> request(
|
||||
stopwatch.stop();
|
||||
return (response, stopwatch.elapsed, null);
|
||||
} catch (e) {
|
||||
if (clientManager.wasRequestCancelled(requestId)) {
|
||||
if (httpClientManager.wasRequestCancelled(requestId)) {
|
||||
return (null, null, kMsgRequestCancelled);
|
||||
}
|
||||
return (null, null, e.toString());
|
||||
} finally {
|
||||
clientManager.closeClient(requestId);
|
||||
httpClientManager.closeClient(requestId);
|
||||
}
|
||||
} else {
|
||||
return (null, null, uriRec.$2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cancelHttpRequest(String? requestId) {
|
||||
httpClientManager.cancelRequest(requestId);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('Testing fromResponse', () async {
|
||||
(HttpResponse?, Duration?, String?)? responseRec = await request(
|
||||
var responseRec = await sendHttpRequest(
|
||||
requestModelGet1.id,
|
||||
requestModelGet1.apiType,
|
||||
requestModelGet1.httpRequestModel!,
|
||||
@ -32,7 +32,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('Testing fromResponse for contentType not Json', () async {
|
||||
(HttpResponse?, Duration?, String?)? responseRec = await request(
|
||||
var responseRec = await sendHttpRequest(
|
||||
requestModelGet13.id,
|
||||
requestModelGet1.apiType,
|
||||
requestModelGet13.httpRequestModel!,
|
||||
@ -48,7 +48,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('Testing fromResponse for Bad SSL with certificate check', () async {
|
||||
(HttpResponse?, Duration?, String?)? responseRec = await request(
|
||||
var responseRec = await sendHttpRequest(
|
||||
requestModelGetBadSSL.id,
|
||||
requestModelGet1.apiType,
|
||||
requestModelGetBadSSL.httpRequestModel!,
|
||||
@ -60,7 +60,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('Testing fromResponse for Bad SSL with no certificate check', () async {
|
||||
(HttpResponse?, Duration?, String?)? responseRec = await request(
|
||||
var responseRec = await sendHttpRequest(
|
||||
requestModelGetBadSSL.id,
|
||||
requestModelGet1.apiType,
|
||||
requestModelGetBadSSL.httpRequestModel!,
|
||||
|
Reference in New Issue
Block a user