From 929a5e07eb06e072574ccdbd0d93510f6433c47a Mon Sep 17 00:00:00 2001 From: Chris Swan <478926+cpswan@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:29:45 +0000 Subject: [PATCH 1/3] ci: Refactor web admin to separate noarch job --- .github/workflows/multibuild.yaml | 52 +++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/.github/workflows/multibuild.yaml b/.github/workflows/multibuild.yaml index f6b6a6e50..cc59baa73 100644 --- a/.github/workflows/multibuild.yaml +++ b/.github/workflows/multibuild.yaml @@ -74,16 +74,8 @@ jobs: with: ref: multibuild-${{github.run_number}} - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # v1.6.5 - - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 - with: - node-version: '20.17.0' - # setup required npm version - - run: | - npm install -g npm@10.8.2 - # create directories need for build - - run: | - mkdir -p sshnp/web/admin - mkdir tarball + # create directory needed for build + - run: mkdir tarball - if: ${{ matrix.os != 'windows-latest' }} run: mkdir sshnp/debug # compile binaries @@ -103,11 +95,6 @@ jobs: run: | dart pub get --enforce-lockfile dart compile exe bin/np_admin.dart -v -o ../../../packages/dart/sshnoports/sshnp/np_admin${{ matrix.ext }} - - name: build admin webapp - working-directory: ./apps/admin/webapp - run: | - npm ci - npm run build - if: ${{ matrix.os != 'windows-latest' }} run: | dart compile exe bin/srvd.dart -v -o sshnp/srvd${{ matrix.ext }} @@ -116,7 +103,6 @@ jobs: - run: | cp -r bundles/core/* sshnp/ cp -r bundles/${{ matrix.bundle }}/* sshnp/ - cp -r ../../../apps/admin/webapp/dist/* sshnp/web/admin/ cp LICENSE sshnp # codesign for apple - if: ${{ matrix.os == 'macos-13' || matrix.os == 'macos-14' }} @@ -217,6 +203,38 @@ jobs: path: ./tarballs/${{ matrix.output-name }}.tgz if-no-files-found: error + web_build: + needs: verify_tags + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: multibuild-${{github.run_number}} + - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: '20.17.0' + # setup required npm version + - run: | + npm install -g npm@10.8.2 + # create directory needed for build + - name: build admin webapp + working-directory: ./apps/admin/webapp + run: | + mkdir -p sshnp/web/admin + mkdir tarball + npm ci + npm run build + cp -r dist/* sshnp/web/admin/ + tar -cvzf tarball/sshnp-web-admin-noarch.tgz sshnp + # upload the build + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: + sshnp-web-admin-noarch-${{github.ref_name}}-${{github.run_number + }}-${{github.run_attempt}} + path: ./apps/admin/webapp/tarball + if-no-files-found: error + universal_sh: if: startsWith(github.ref, 'refs/tags/v') defaults: @@ -261,7 +279,7 @@ jobs: github-release: name: >- Upload artifacts and generate SBOMs and checksums for provenance - needs: [main_build, other_build, universal_sh, universal_ps1] + needs: [main_build, other_build, web_build, universal_sh, universal_ps1] runs-on: ubuntu-latest outputs: hashes: ${{ steps.hash.outputs.hashes }} From 277612c9c6c3becc62a7e613b36d8b0c22b57e9b Mon Sep 17 00:00:00 2001 From: Chris Swan <478926+cpswan@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:01:37 +0000 Subject: [PATCH 2/3] fix: Ensure that sshnp directory is created --- .github/workflows/multibuild.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/multibuild.yaml b/.github/workflows/multibuild.yaml index cc59baa73..edfb465b7 100644 --- a/.github/workflows/multibuild.yaml +++ b/.github/workflows/multibuild.yaml @@ -74,8 +74,10 @@ jobs: with: ref: multibuild-${{github.run_number}} - uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672 # v1.6.5 - # create directory needed for build - - run: mkdir tarball + # create directories needed for build + - run: | + mkdir sshnp + mkdir tarball - if: ${{ matrix.os != 'windows-latest' }} run: mkdir sshnp/debug # compile binaries From 46ea602a3aa6ff275b40ade1724c2c6c0f19df1b Mon Sep 17 00:00:00 2001 From: XavierChanth Date: Tue, 19 Nov 2024 08:50:51 -0500 Subject: [PATCH 3/3] feat(npt_flutter): add profile duplicate button --- .../features/profile/bloc/profile_bloc.dart | 6 +++++ .../features/profile/bloc/profile_event.dart | 3 ++- .../widgets/profile_popup_menu_button.dart | 22 ++++++++++++++++++- .../profile_form/view/profile_form_view.dart | 5 +++-- .../widgets/profile_list_add_button.dart | 3 ++- .../lib/pages/profile_form_page.dart | 11 ++++++++-- packages/dart/npt_flutter/macos/Podfile.lock | 2 +- packages/dart/npt_flutter/pubspec.lock | 6 ++--- 8 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/dart/npt_flutter/lib/features/profile/bloc/profile_bloc.dart b/packages/dart/npt_flutter/lib/features/profile/bloc/profile_bloc.dart index 4c1167bab..24ca5ae11 100644 --- a/packages/dart/npt_flutter/lib/features/profile/bloc/profile_bloc.dart +++ b/packages/dart/npt_flutter/lib/features/profile/bloc/profile_bloc.dart @@ -52,6 +52,12 @@ class ProfileBloc extends LoggingBloc { profile = null; } + if (event.copyFrom != null) { + var json = event.copyFrom!.toJson(); + json["uuid"] = uuid; + profile = Profile.fromJson(json); + } + if (profile == null) { emit(ProfileLoaded( uuid, diff --git a/packages/dart/npt_flutter/lib/features/profile/bloc/profile_event.dart b/packages/dart/npt_flutter/lib/features/profile/bloc/profile_event.dart index 9804a9881..d2389d37e 100644 --- a/packages/dart/npt_flutter/lib/features/profile/bloc/profile_event.dart +++ b/packages/dart/npt_flutter/lib/features/profile/bloc/profile_event.dart @@ -18,7 +18,8 @@ final class ProfileLoadEvent extends ProfileEvent { } final class ProfileLoadOrCreateEvent extends ProfileEvent { - const ProfileLoadOrCreateEvent(); + final Profile? copyFrom; + const ProfileLoadOrCreateEvent({this.copyFrom}); @override String toString() { diff --git a/packages/dart/npt_flutter/lib/features/profile/widgets/profile_popup_menu_button.dart b/packages/dart/npt_flutter/lib/features/profile/widgets/profile_popup_menu_button.dart index f0818af8b..fad029199 100644 --- a/packages/dart/npt_flutter/lib/features/profile/widgets/profile_popup_menu_button.dart +++ b/packages/dart/npt_flutter/lib/features/profile/widgets/profile_popup_menu_button.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/app.dart'; import 'package:npt_flutter/features/profile/profile.dart'; +import 'package:npt_flutter/pages/profile_form_page.dart'; import 'package:npt_flutter/features/profile_list/bloc/profile_list_bloc.dart'; import 'package:npt_flutter/styles/sizes.dart'; import 'package:npt_flutter/widgets/custom_snack_bar.dart'; @@ -10,6 +11,7 @@ import 'package:phosphor_flutter/phosphor_flutter.dart'; import '../../../routes.dart'; import '../../../util/export.dart'; +import '../../../util/uuid.dart'; import '../../../widgets/confirmation_dialog.dart'; import '../../../widgets/multi_select_dialog.dart'; @@ -41,10 +43,28 @@ class ProfilePopupMenuButton extends StatelessWidget { } if (context.mounted) { - Navigator.of(context).pushNamed(Routes.profileForm, arguments: state.profile.uuid); + Navigator.of(context) + .pushNamed(Routes.profileForm, arguments: ProfileFormPageArguments(state.profile.uuid)); } }, ), + PopupMenuItem( + child: Row( + children: [ + PhosphorIcon(PhosphorIcons.copy()), + gapW10, + const Text("Duplicate"), // TODO: localizations + ], + ), + onTap: () { + var state = context.read().state; + if (state is! ProfileLoadedState) return; + var copyFrom = state.profile; + if (context.mounted) { + Navigator.of(context).pushNamed(Routes.profileForm, + arguments: ProfileFormPageArguments(Uuid.generate(), copyFrom: copyFrom)); + } + }), PopupMenuItem( child: Row( children: [ diff --git a/packages/dart/npt_flutter/lib/features/profile_form/view/profile_form_view.dart b/packages/dart/npt_flutter/lib/features/profile_form/view/profile_form_view.dart index 7f1ede75c..96004b971 100644 --- a/packages/dart/npt_flutter/lib/features/profile_form/view/profile_form_view.dart +++ b/packages/dart/npt_flutter/lib/features/profile_form/view/profile_form_view.dart @@ -8,7 +8,8 @@ import 'package:npt_flutter/widgets/custom_card.dart'; class ProfileFormView extends StatelessWidget { final String uuid; - const ProfileFormView(this.uuid, {super.key}); + final Profile? copyFrom; + const ProfileFormView(this.uuid, {super.key, this.copyFrom}); @override Widget build(BuildContext context) { @@ -19,7 +20,7 @@ class ProfileFormView extends StatelessWidget { create: (BuildContext context) => /// Local copy of the profile which is used by the form - ProfileBloc(context.read(), uuid)..add(const ProfileLoadOrCreateEvent()), + ProfileBloc(context.read(), uuid)..add(ProfileLoadOrCreateEvent(copyFrom: copyFrom)), child: Padding( padding: const EdgeInsets.only(left: Sizes.p100, right: Sizes.p100), child: Stack( diff --git a/packages/dart/npt_flutter/lib/features/profile_list/widgets/profile_list_add_button.dart b/packages/dart/npt_flutter/lib/features/profile_list/widgets/profile_list_add_button.dart index f353afeba..b17843524 100644 --- a/packages/dart/npt_flutter/lib/features/profile_list/widgets/profile_list_add_button.dart +++ b/packages/dart/npt_flutter/lib/features/profile_list/widgets/profile_list_add_button.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/routes.dart'; +import 'package:npt_flutter/pages/profile_form_page.dart'; import 'package:npt_flutter/styles/sizes.dart'; import 'package:npt_flutter/util/uuid.dart'; import 'package:phosphor_flutter/phosphor_flutter.dart'; @@ -25,7 +26,7 @@ class ProfileListAddButton extends StatelessWidget { onPressed: () { final uuid = Uuid.generate(); if (context.mounted) { - Navigator.of(context).pushNamed(Routes.profileForm, arguments: uuid); + Navigator.of(context).pushNamed(Routes.profileForm, arguments: ProfileFormPageArguments(uuid)); } }, label: Text(strings.addNew), diff --git a/packages/dart/npt_flutter/lib/pages/profile_form_page.dart b/packages/dart/npt_flutter/lib/pages/profile_form_page.dart index 9b19939a6..75723241b 100644 --- a/packages/dart/npt_flutter/lib/pages/profile_form_page.dart +++ b/packages/dart/npt_flutter/lib/pages/profile_form_page.dart @@ -1,18 +1,25 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:npt_flutter/features/profile_form/profile_form.dart'; +import 'package:npt_flutter/features/profile/models/profile.dart'; import 'package:npt_flutter/widgets/npt_app_bar.dart'; +class ProfileFormPageArguments { + final String uuid; + final Profile? copyFrom; + ProfileFormPageArguments(this.uuid, {this.copyFrom}); +} + class ProfileFormPage extends StatelessWidget { const ProfileFormPage({super.key}); @override Widget build(BuildContext context) { - final uuid = ModalRoute.of(context)!.settings.arguments as String; + final args = ModalRoute.of(context)!.settings.arguments as ProfileFormPageArguments; final strings = AppLocalizations.of(context)!; return Scaffold( appBar: NptAppBar(title: strings.addNewProfile), - body: ProfileFormView(uuid), + body: ProfileFormView(args.uuid, copyFrom: args.copyFrom), ); } } diff --git a/packages/dart/npt_flutter/macos/Podfile.lock b/packages/dart/npt_flutter/macos/Podfile.lock index e47331eb8..baec81b66 100644 --- a/packages/dart/npt_flutter/macos/Podfile.lock +++ b/packages/dart/npt_flutter/macos/Podfile.lock @@ -87,4 +87,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/packages/dart/npt_flutter/pubspec.lock b/packages/dart/npt_flutter/pubspec.lock index 3a7b544e4..9a1048c72 100644 --- a/packages/dart/npt_flutter/pubspec.lock +++ b/packages/dart/npt_flutter/pubspec.lock @@ -939,7 +939,7 @@ packages: path: "../noports_core" relative: true source: path - version: "6.2.0" + version: "6.2.1" openssh_ed25519: dependency: transitive description: @@ -1317,10 +1317,10 @@ packages: dependency: "direct main" description: name: socket_connector - sha256: "3c641546699aa58e9ab8be9841627a30af3c1ffcf4461ca5d00d7c56392ab63a" + sha256: "091c83fb214f6ff48dbf38f6e011e148d996cce05487303c5e8a0cd72369b0e2" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.3" source_gen: dependency: transitive description: