1212        <div  style =" padding  : 6px   8px   6px   8px  "  >
1313          <span  class =" input"  >User:</span >
1414          <span  class =" select"  >
15-             <Select  v-model =" selectedUser "   filter  :options =" users"   :optionLabel =" label"   />
15+             <Select  v-model =" selected.user "   filter  :options =" users"   :optionLabel =" label"   />
1616          </span >
1717
1818          <span  class =" input"  >Repo:</span >
1919          <span  class =" select"  >
20-             <Select  v-model =" selectedRepo "   filter  :options =" repos"   :optionLabel =" label"   />
20+             <Select  v-model =" selected.repo "   filter  :options =" repos"   :optionLabel =" label"   />
2121          </span >
2222
23-           <DropDownWithCount  v-model =" selectedTarget "   tag =" Target"   :all =" ALL_TARGETS"   :counts =" targets"   />
23+           <DropDownWithCount  v-model =" selected.target "   tag =" Target"   :all =" ALL_TARGETS"   :counts =" targets"   />
2424
2525        </div >
2626
2727        <div  style =" padding  : 2px   8px   10px   8px  "  >
2828
29-           <DropDownWithCount  v-model =" selectedChecker "   tag =" Checker "   :all =" ALL_CHECKERS "   :counts =" checkers "   />
30-           <DropDownWithCount  v-model =" selectedKind "   tag =" Kind "   :all =" ALL_KINDS "   :counts =" kinds "   />
29+           <DropDownWithCount  v-model =" selected.pkg "   tag =" Pkg "   :all =" ALL_PKGS "   :counts =" pkgs "   />
30+           <DropDownWithCount  v-model =" selected.features "   tag =" Features "   :all =" ALL_FEATURES_SETS "   :counts =" features "   />
3131
32-           <DropDownWithCount  v-model =" selectedPkg"   tag =" Pkg"   :all =" ALL_PKGS"   :counts =" pkgs"   />
33- 
34-           <DropDownWithCount  v-model =" selectedFeatures"   tag =" Features"   :all =" ALL_FEATURES_SETS"   :counts =" features"   />
35-           <!--  <span class="input">Features:</span> --> 
36-           <!--  <span class="select"> --> 
37-           <!--    <Select v-model="selectedFeatures" filter showClear :options="features" :optionLabel="label" --> 
38-           <!--      placeholder="" /> --> 
39-           <!--  </span> --> 
32+           <DropDownWithCount  v-model =" selected.checker"   tag =" Checker"   :all =" ALL_CHECKERS"   :counts =" checkers"   />
33+           <DropDownWithCount  v-model =" selected.kind"   tag =" Kind"   :all =" ALL_KINDS"   :counts =" kinds"   />
4034
4135        </div >
4236      </div >
4337
4438    </div >
4539
46-     <FileTree2  :get =" got2"   :count =" count"   v-model:filters =" displayFilters"   />
40+     <FileTree2  :get =" got2"   :count =" count"   v-model:filters =" displayFilters"   v-model:lockURL = " lockURL "   />
4741  </div >
4842</template >
4943
5044<script  lang="ts" setup>
51- import  { cloneDeep  } from  ' es-toolkit/compat'  ;
45+ import  { cloneDeep ,  includes  } from  ' es-toolkit/compat'  ;
5246import  type  { FetchError  } from  ' ofetch'  ;
5347import  { Severity , type  FileTree  } from  ' ~/shared/file-tree'  ;
5448import  { Dropdown , gen_map , gen_targets  } from  ' ~/shared/file-tree/dropdown'  ;
@@ -62,13 +56,25 @@ highlightRust();
6256
6357const   label =  (a :  string ) =>  a ;
6458
65- const   selectedUser =  ref (" "  );
66- const   selectedRepo =  ref (" "  );
67- const   selectedPkg =  ref <string  |  null >(null );
68- const   selectedChecker =  ref <string  |  null >(null );
69- const   selectedKind =  ref <string  |  null >(null );
70- const   selectedTarget =  ref (ALL_TARGETS );
71- const   selectedFeatures =  ref <string  |  null >(null );
59+ const   selected =  reactive <{
60+   user:  string , 
61+   repo:  string , 
62+   target:  string  |  null , 
63+   pkg:  string  |  null , 
64+   features:  string  |  null , 
65+   checker:  string  |  null , 
66+   kind:  string  |  null , 
67+ }>({ 
68+   user: " "  , 
69+   repo: " "  , 
70+   target: ALL_TARGETS , 
71+   pkg: null , 
72+   features: null , 
73+   checker: null , 
74+   kind: null , 
75+ }); 
76+ //  watch(selected, val => console.log(val));
77+ 
7278const   displayFilters =  ref (true );
7379
7480const   got =  ref <Get >(getEmpty ());
@@ -82,26 +88,54 @@ githubFetch<UserRepo>({ path: "ui/user_repo.json" })
8288
8389//  Init filters.
8490const   users =  computed (() =>  Object .keys (user_repo .value ).sort ());
85- watch (users , (val ) =>  selectedUser .value  =  val [0 ] ??  " "  );
86- const   repos =  computed (() =>  user_repo .value [selectedUser .value ]);
87- watch (repos , (val ) =>  selectedRepo .value  =  val [0 ] ??  " "  );
91+ const   repos =  computed (() =>  user_repo .value [selected .user ]);
92+ const   targets =  computed <DropDownOptions >(() =>  {
93+   const   t =  basic .value ?.targets ; 
94+   return  t  ?  gen_targets (t ) :  emptyOptions (); 
95+ }); 
96+ 
97+ const   lockURL =  ref (false );
98+ type  Params  =  {
99+   user? :  string , 
100+   repo? :  string , 
101+   target? :  string , 
102+   pkg? :  string , 
103+   features? :  string , 
104+   checker? :  string , 
105+   kind? :  string , 
106+   lock? :  string , 
107+ }; 
108+ //  given query
109+ const   query_params =  reactive <Params >({});
110+ 
111+ //  init user & repo, considering route query if any
112+ watch (user_repo , val  =>  {
113+   const   { user, repo, target } =  query_params ; 
114+   if  (user  &&  repo ) { 
115+     selected .user  =  user ; 
116+     selected .repo  =  repo ; 
117+     if  (target  &&  target  !==  ALL_TARGETS ) selected .target  =  target ; 
118+   } else  { 
119+     const   user =  Object .keys (val ).sort ()[0 ] ??  " "  ; 
120+     selected .user  =  user ; 
121+     selected .repo  =  val [user ][0 ] ??  " "  ; 
122+   } 
123+ }); 
88124
89125//  Update got state.
90- watch (() =>  ({ user: selectedUser . value , repo: selectedRepo . value , target: selectedTarget . value  }),
126+ watch (() =>  ({ user: selected . user , repo: selected . repo , target: selected . target  }),
91127  ({ user , repo , target  }) =>  { 
92-     if  (user  &&  repo ) { 
93-       const   target_ =  target  ||  ALL_TARGETS ; 
94-       get (` ui/repos/${user }/${repo }/${target_ }.json ` ); 
128+     if  (user  &&  includes (repos .value , repo )) { 
129+       get (` ui/repos/${user }/${repo }/${target  ||  ALL_TARGETS }.json ` ); 
95130      getBasic (` ui/repos/${user }/${repo }/basic.json ` ); 
131+     } else  if  (user  &&  repos .value [0 ]) { 
132+       //  repo is not present, maybe user is selected, but not for repo 
133+       selected .repo  =  repos .value [0 ]; 
134+       selected .target  =  ALL_TARGETS ; 
96135    } 
97136  } 
98137); 
99138
100- const   targets =  computed <DropDownOptions >(() =>  {
101-   const   t =  basic .value ?.targets ; 
102-   return  t  ?  gen_targets (t ) :  emptyOptions (); 
103- }); 
104- 
105139const   pkgs =  ref (emptyOptions ());
106140const   kinds =  ref (emptyOptions ());
107141const   checkers =  ref (emptyOptions ());
@@ -128,17 +162,19 @@ function get_ck_kinds(ck: string | null): string[] | null {
128162  } 
129163  return  null ; 
130164} 
131- //  switch to another Get
132- watch (got , g  =>  {
165+ 
166+ function  switch_got(g :  Get ) {
167+   if  (lock_filters ()) return ; 
168+ 
133169  //  reset pkg and features since it's less likely to see the same selected pkg in another repo 
134-   selectedPkg . value  =  null ; 
135-   selectedFeatures . value  =  null ; 
170+   selected . pkg  =  null ; 
171+   selected . features  =  null ; 
136172
137173  //  reset kind if the diagnositc is empty 
138-   selectedKind . value  =  Dropdown .find_kind (selectedKind . value , g ); 
174+   selected . kind  =  Dropdown .find_kind (selected . kind , g ); 
139175
140176  //  reset checker if the diagnositc is empty 
141-   const   ck_kinds =  get_ck_kinds (selectedChecker . value ); 
177+   const   ck_kinds =  get_ck_kinds (selected . checker ); 
142178  let  reset_checker =  true ; 
143179  if  (ck_kinds ) { 
144180    for  (const   kind of  ck_kinds ) { 
@@ -148,27 +184,47 @@ watch(got, g => {
148184      } 
149185    } 
150186  } 
151-   if  (reset_checker ) selectedChecker .value  =  null ; 
152- }); 
187+   if  (reset_checker ) selected .checker  =  null ; 
188+ } 
189+ 
190+ function  lock_filters():  boolean  {
191+   const   init =  query_params .lock  ===  " true"  ; 
192+   //  should be called only once in startup 
193+   if  (init ) { 
194+     lockURL .value  =  true ; 
195+     const   { pkg, features, checker, kind } =  query_params ; 
196+     if  (pkg ) selected .pkg  =  pkg ; 
197+     if  (features ) selected .features  =  features ; 
198+     if  (checker ) selected .checker  =  checker ; 
199+     if  (kind ) selected .kind  =  kind ; 
200+     query_params .lock  =  undefined ; 
201+   } 
202+   return  init ; 
203+ } 
153204
154205//  watch selection changes
155206watch (
156207  () =>  ({ 
157-     pkg: selectedPkg .value , feat: selectedFeatures .value , 
158-     kind: selectedKind .value , ck: selectedChecker .value , g: got .value  
208+     pkg: selected .pkg , feat: selected .features , 
209+     kind: selected .kind , ck: selected .checker , 
210+     g: got .value , b: basic .value  
159211  }), 
160-   ({ pkg , feat , kind , ck , g  }) =>  { 
161-     const   target =  cloneDeep (g ); 
212+   ({ pkg , feat , kind , ck , g  }, old ) =>  { 
213+     if  (old .g  !==  g ) return  switch_got (g ); 
214+     lockURL .value  =  false ; 
162215
163-     Dropdown .update_by_features (feat , target ); 
164-     Dropdown .update_by_pkg (pkg , target ); 
216+     const   val =  cloneDeep (g ); 
165217
218+     Dropdown .update_by_features (feat , val ); 
219+     Dropdown .update_by_pkg (pkg , val ); 
220+ 
221+     //  get_ck_kinds relies on basic: if basic is not ready, spurious null is got 
166222    const   ck_kinds =  get_ck_kinds (ck ); 
167-     if  (ck_kinds ) Dropdown .update_by_checker (ck_kinds , target ); 
223+     if  (ck_kinds ) Dropdown .update_by_checker (ck_kinds , val ); 
168224
169-     Dropdown .update_by_kind (kind , target ); 
225+     Dropdown .update_by_kind (kind , val ); 
170226
171-     got2 .value  =  target ; 
227+     got2 .value  =  val ; 
172228  } 
173229); 
174230
@@ -220,7 +276,7 @@ function get(path: string) {
220276      //    kind: "Not Exists!", raw: ["该目标架构下,无原始报告数据。"], 
221277      //    lang: "rust", severity: Severity.Danger, disabled: false 
222278      //  }]; 
223-       //  selectedTab .value = "Not Exists!"; 
279+       //  selected.tab .value = "Not Exists!"; 
224280      //  fileTree.value = { kinds_order: [], data: [] }; 
225281    }); 
226282} 
@@ -230,6 +286,53 @@ function getBasic(path: string) {
230286    .then (val  =>  basic .value  =  val ) 
231287    .catch (err  =>  console .log (err )) 
232288} 
289+ 
290+ //  route query
291+ const   route =  useRoute ();
292+ function  updateFilter(query :  Params ) {
293+   const   { user, repo, target, pkg, features, checker, kind, lock } =  query ; 
294+ 
295+   if  (user ) { query_params .user  =  decodeURIComponent (user ); } 
296+   if  (repo ) { query_params .repo  =  decodeURIComponent (repo ); } 
297+   if  (target ) { query_params .target  =  decodeURIComponent (target ); } 
298+   if  (pkg ) { query_params .pkg  =  decodeURIComponent (pkg ); } 
299+   if  (features  !==  undefined ) { query_params .features  =  decodeURIComponent (features ); } 
300+   if  (checker ) { query_params .checker  =  decodeURIComponent (checker ); } 
301+   if  (kind ) { query_params .kind  =  decodeURIComponent (kind ); } 
302+   if  (lock  ===  " true"  ) { 
303+     query_params .lock  =  decodeURIComponent (lock ); 
304+     lockURL .value  =  false ; 
305+   } 
306+ } 
307+ updateFilter (route .query );
308+ 
309+ const   router =  useRouter ();
310+ //  emit query
311+ const   router_params =  ref <Params  |  null >(null );
312+ watch (router_params , query  =>  router .push ({ path: route .path , query: query  ||  {} }));
313+ 
314+ watch (lockURL , lock  =>  {
315+   if  (! lock ) { 
316+     router_params .value  =  {}; 
317+     return ; 
318+   } 
319+ 
320+   const   { user, repo, target, pkg, features, checker, kind } =  selected ; 
321+ 
322+   let  query:  any  =  {}; 
323+ 
324+   if  (user ) query .user  =  encodeURIComponent (user ); 
325+   if  (repo ) query .repo  =  encodeURIComponent (repo ); 
326+   if  (target  &&  target  !==  ALL_TARGETS ) query .target  =  encodeURIComponent (target ); 
327+   if  (pkg ) query .pkg  =  encodeURIComponent (pkg ); 
328+   if  (features  !==  null ) query .features  =  encodeURIComponent (features ); 
329+   if  (checker ) query .checker  =  encodeURIComponent (checker ); 
330+   if  (kind ) query .kind  =  encodeURIComponent (kind ); 
331+ 
332+   query .lock  =  encodeURIComponent (" true"  ); 
333+ 
334+   router_params .value  =  query ; 
335+ }); 
233336 </script >
234337
235338<!--  FIXME: remove these --> 
@@ -244,22 +347,4 @@ function getBasic(path: string) {
244347.select  {
245348  padding-right  : 10px  ; 
246349} 
247- 
248- .resolved-table  {
249-   --p-datatable-header-cell-color : var (--p-button-primary-background ); 
250- } 
251- 
252- .sources  {
253-   color  : var (--p-orange-400 ); 
254- } 
255- 
256- .sources-table  {
257-   --p-datatable-header-cell-color : var (--p-orange-400 ); 
258- } 
259- 
260- .drop-down-options  {
261-   margin-right  : 8px  ; 
262-   width  : 40px  ; 
263-   justify-content  : right ; 
264- } 
265350 </style >
0 commit comments